I have a many-to-many relationship between Department and Employee
I have already done a mapping for the GET endpoint which returns a list of departments that contain Employees, this is the request: http://localhost:8080/api/departments/1/employees
, and this is the response I get:
[ { "id": { "deptNo": "1 ", "empNo": 2 }, "fromDate": "2021-11-22", "toDate": null } ]
This is the code that gets the job done:
Department Repository Imp
@Override public Optional<Department> findByIdWithEmployees(String deptNo) { TypedQuery<Department> query = this.entityManager.createQuery("SELECT d FROM Department d JOIN FETCH d.employees e WHERE d.deptNo = :deptNo AND e.toDate IS NULL", Department.class).setParameter("deptNo", deptNo); return Optional.ofNullable(query.getSingleResult()); }
Employee Service Impl
@Override public List<DepartmentEmployee> listAllEmployeesPerDepartment(String deptNo) { Department department = this.departmentRepository.findByIdWithEmployees(deptNo).orElseThrow(() -> new DepartmentNotFoundException(deptNo)); return department.getEmployees(); }
Department Controller
@GetMapping("/{deptNo}/employees") public List<DepartmentEmployee> getEmployeesPerDepartment(@PathVariable String deptNo) { return this.employeeService.listAllEmployeesPerDepartment(deptNo); }
Now what I need is to re-map this so I get a different response. This is the response I need to receive when I run a GET request:
[ { "fromDate":"2021-11-22", "toDate":null, "employee":{ "empNo":2, "birthDate":"1997-05-10", "firstName":"Taulant", "lastName":"Fazliu", "gender":"M", "hireDate":"2020-01-01" } } ]
How to achieve this?
Advertisement
Answer
If the response you want to give has a different structure from your model (the first diagram you showed), you need to implement the DTO pattern.
DTO: Data Transfer Object. It just means, in words of Samuel L. Jackson “hey you! Do you want to show your shit in a different way? Create a new mother fucker object that represents the new shit, and damn transform it!“
So, create a new object called DepartmentEmployeeDTO
with the structure you want to show, and use a Builder
pattern to transform from one to another. And of course make getEmployeesPerDepartment
return List<DepartmentEmployeeDTO>
. That method will end up as something like this:
@GetMapping("/{deptNo}/employees") public List<DepartmentEmployeeDTO> getEmployeesPerDepartment(@PathVariable String deptNo) { return this.employeeService.listAllEmployeesPerDepartment(deptNo) .stream() .map(e -> new DepartmentEmployeeDTOBuilder(e).build()) .collect(Collectors.toList()); }
That provided you build you Builder
with one constructor with the original DepartmentEmployee
as the only parameter.