Статьи

JSON — Джексон на помощь

Иногда вам нужно получить некоторые данные с сервера в JavaScript, JSON является довольно хорошим выбором для этой задачи.

Давайте поиграем с примером «Работодатель — Сотрудник — Выгода» из отображений JPA Demystified (эпизод 1) — @OneToMany и @ManyToOne . Мы будем использовать его внутри веб-приложения на основе Spring Framework .

Наш первый контроллер вернет список сотрудников в качестве тела ответа, в нашем случае MappingJacksonHttpMessageConverter будет автоматически использоваться для преобразования значения, возвращаемого методом handleGet, в ответ, отправляемый клиенту.

01
02
03
04
05
06
07
08
09
10
11
12
@Controller
@RequestMapping('/employee-list.json')
public class EmployeeListController {
    @Autowired
    private EmployerDAO employerDAO;
 
    @RequestMapping(method = RequestMethod.GET)
    @ResponseBody
    public List<Employee> handleGet(@RequestParam('employerId') Long employerId) {
        return employerDAO.getEmployees(employerId);
    }
}

Когда мы пытаемся получить данные в первый раз, мы сталкиваемся с красивым исключением: JsonMappingException: бесконечная рекурсия (StackOverflowError) — вызвано двунаправленными ссылками между Employer — Employee — Benefit.

В поисках возможного решения я обнаружил заметку Обработка двунаправленных ссылок, используя декларативный метод (ы) , и после прочтения я исправил сущности домена следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
@Entity
@Table(name = 'EMPLOYERS')
public class Employer implements Serializable {
...
    @JsonManagedReference('employer-employee')
    @OneToMany(mappedBy = 'employer', cascade = CascadeType.PERSIST)
    public List
 
                       getEmployees() {
        return employees;
    }
...
}
 
@Entity
@Table(name = 'EMPLOYEES')
public class Employee implements Serializable {
...
    @JsonManagedReference('employee-benefit')
    @OneToMany(mappedBy = 'employee', cascade = CascadeType.PERSIST)
    public List
 
                        getBenefits() {
        return benefits;
    }
 
    @JsonBackReference('employer-employee')
    @ManyToOne(optional = false)
    @JoinColumn(name = 'EMPLOYER_ID')
    public Employer getEmployer() {
        return employer;
    }
...
}
 
@Entity
@Table(name = 'BENEFITS')
public class Benefit implements Serializable {
...
    @JsonBackReference('employee-benefit')
    @ManyToOne(optional = false)
    @JoinColumn(name = 'EMPLOYEE_ID')
    public Employee getEmployee() {
        return employee;
    }
...
}

После внесения вышеуказанных изменений я наконец смог получить ответ JSON, возвращаемый моим кодом:

1
[{'id':1, 'benefits':[{'name':'Healthy Employees', 'id':1, 'type':'HEALTH_COVERAGE', 'startDate':1104534000000, 'endDate':null}, {'name':'Gold Autumn','id':2,'type':'RETIREMENT_PLAN','startDate':1104534000000,'endDate':null},{'name':'Always Secured','id':3,'type':'GROUP_TERM_LIFE','startDate':1104534000000,'endDate':null}],'firstName':'John'},{'id':2,'benefits':[],'firstName':'Mary'},{'id':3,'benefits':[],'firstName':'Eugene'}]

И как обычно несколько ссылок на десерт:

Справка: JSON — Джексон на помощь от нашего партнера по JCG Миха? Ja? Tak в блоге Мысли Чернокнижника