I've been checking similar issues and haven't found any answer addressing what I am observing.
The issue is that I've easily managed to get Hypermedia in HAL format in my REST API when I retrieve 1 resource, but when I hit the controller methods retrieving a list of entities, then the hypermedia is NOT the same.
Here are the ouputs:
single resource returned
"_links": { "self": { "href": "http://localhost:8080/celsvs/api/books/123567891099" }, "books": { "href": "http://localhost:8080/celsvs/api/books" } }
List of resources
"links": [ { "rel": "self", "href": "http://localhost:8080/celsvs/api/books/123567891099" }, { "rel": "books", "href": "http://localhost:8080/celsvs/api/books" } ]
I started with Spring hateoas 0.25, but as I had to uplift anyway Spring boot and I saw that the Hateoas API had changed, I am now on Spring hateoas 1.0... And even after adapting my code to the new API I am still getting the same result.
I am using the RepresentationModelAssemblerSupport class to keep my controllers clean from code to generate hateoas content. So this is how it looks like:
@Component
public class BookModelAssembler extends RepresentationModelAssemblerSupport<BookDto, BookDto> {
public BookModelAssembler() {
super(BooksController.class, BookDto.class);
}
@Override
public BookDto toModel(BookDto entity) {
return entity.add(linkTo(methodOn(BooksController.class).getResource(entity.getIsbn())).withSelfRel())
.add(linkTo(methodOn(BooksController.class).getAllResources()).withRel("books"));
}
}
And in the Controller, the endpoints to retrieve one or all resources:
@Override
@GetMapping(value = {QueryConstants.BOOKS_ISBN_PATH, QueryConstants.BOOKS_SIG_PATH})
public BookDto getResource(@PathVariable("isbn") final String isbn) {
return this.modelAssembler.toModel(this.findOneResource(isbn));
}
// GET - retrieve all resources
@Override
@GetMapping (produces = { "application/hal+json" })
public List<BookDto> getAllResources() {
return (findAllResources().stream().map(this.modelAssembler::toModel).collect(Collectors.toList()));
}
As you can see, the Hypermedia rendered is different even when all the entities in the list returned have been mapped using the same method toModel() used in the method getResource().
The only way I've managed to see in the case of all resources the proper HAL format returned is when I've changed the implementation of the controller to return a collection Model:
//@GetMapping
public CollectionModel<BookDto> getAll() {
return this.modelAssembler.toCollectionModel(findAllResources());
}
but then all the entities are bundled inside an _embedded element, which is NOT what I want when I return the collection of entities.
Spring Hateoas documentation states that HAL is the default, so I have not thought about configuring anything for now...
So, I only see:
Does anyone have any advice? I am running out of time and ideas and the team implementing the client side is waiting to consume the Hypermedia content. Thanks!
The HAL specification says that the property _embedded
is used to store an array of resource object.
Edit: To answer Alberto's question in his own answer
Still, if someone can tell me why in the previous implementation the attached links did not follow the HAL format, I would appreciate. Thanks
Spring HATEOAS customizes JSON serialization of RepresentationModel
which is the parent class of CollectionModel
.
// org.springframework.hateoas.mediatype.hal.RepresentationModelMixin
public abstract class RepresentationModelMixin extends RepresentationModel<RepresentationModelMixin> {
@Override
@JsonProperty("_links")
@JsonInclude(Include.NON_EMPTY)
@JsonSerialize(using = Jackson2HalModule.HalLinkListSerializer.class)
@JsonDeserialize(using = Jackson2HalModule.HalLinkListDeserializer.class)
public abstract Links getLinks();
}
@JsonProperty("_links")
defines the JSON property name to be _links
. @JsonSerialize defines the serializer to be used. Look into method org.springframework.hateoas.mediatype.hal.Jackson2HalModule.HalLinkListSerializer#serialize
for serialization logic.