I'm developing Spring HATEOAS REST api. Now I encountered a need to hide some fields of Employee class (I want to hide some of them).
As far as i understand DTO (data transfer objects) must be used. So i created new class (EmployeeDTO) with only this fields, that I need. I am using ModelMapper to map appropriate fields.
So now, I have a problem with data types. Do i have to change all return values in my Controller from Employee to EmployeeDTO? And then change everything in ModelAssembler?
Or maybe DTO class should extends RepresentationModel? (This forces to extends it in Entity too).
Looking forward for your help, all of this looks kinda messy (changing all return types) and I feel like there should be smarter solution.
That's how am I doing it right now:
Methods in EmployeeController:
@GetMapping(value = "/{id}", produces = "application/hal+json")
public EntityModel<Employee> getEmployeeById(@PathVariable Long id) {
Optional<Employee> employee = employeeService.findById(id);
return employeeModelAssembler.toModel(employee.get());
}
@GetMapping(value = "", produces = "application/hal+json")
public CollectionModel<EntityModel<Employee>> getAllEmployees() {
List<Employee> employeesList = EmployeeService.findall();
return employeeModelAssembler.toCollectionModel(EmployeesList);
}
EmployeeModelAssembler (autowired in Controller):
public class EmployeeModelAssembler implements RepresentationModelAssembler<Employee, EntityModel<Employee>> {
@Override
public EntityModel<Employee> toModel(Employee employee) {
EntityModel<Employee> employeeEntityModel = EntityModel.of(employee);
Link selfLink = linkTo(methodOn(EmployeeController.class).getEmployeeById(employee.getId())).withSelfRel();
employeeEntityModel.add(selfLink);
return employeeEntityModel;
}
@Override
public CollectionModel<EntityModel<Employee>> toCollectionModel(Iterable<? extends Employee> entities) {
List<Employee> employeesList = (List<Employee>) entities;
List<EntityModel<Employee>> employeeEML = employeesList.stream().map(this::toModel).collect(Collectors.toList());
Link selfLink = linkTo(methodOn(EmployeeController.class).getAllEmployees()).withSelfRel();
return CollectionModel.of(employeeEML, selfLink);
}
}
EDIT
This is the way I'm accessing this hal+json response in another controller. The goal is to get List of EmployeeDTO objects:
String uri = "http://localhost:8080/api/employees";
Traverson traverson = new Traverson(URI.create(uri), MediaTypes.HAL_JSON);
Traverson.TraversalBuilder tb = traverson.follow("href");
ParameterizedTypeReference<CollectionModel<EmployeeDTO>> typeReference = new ParameterizedTypeReference<CollectionModel<EmployeeDTO>>() {};
CollectionModel<EmployeeDTO> resEmployees = tb.toObject(typeReference);
Collection<EmployeeDTO> employees = resEmployees.getContent();
ArrayList<EmployeesDTO> employeesList = new ArrayList<>(employees);
for(EmployeesDTO x : employeesList) {
System.out.println(x);
System.out.println(x.getLinks());
}