I'm trying to convert the result of a paged query to a PagedModel to generate the links automatically. Basically, the endpoint in the controller will return ResponseEntity<PagedModel<EntityModel<MyEntityProjection>>>, instead of returning Page<MyEntityProjection>.
For the client to get the list, usually the request will change from 'data.content' to 'data._embedded.myEntities'. I was able to make that conversion using PagedResourcesAssembler, but it only seems to work for custom queries using Query Lookup Strategies, but not with @Query.
Here's the code.
Repository:
@RepositoryRestResource
public interface MyEntityRepository extends PagingAndSortingRepository<MyEntity, Long>{
Page<MyEntityProjection> findAllByMyField(String value, Pageable pageable);
@Query("...")
Page<MyEntityProjection> findAllByMyFieldButWithQuery(String value, Pageable pageable);
@Query(value = "...", nativeQuery = true)
Page<MyEntityProjection> findAllByMyFieldButWithNativeQuery(String value, Pageable pageable);
}
The repository is doing the same query in three different ways. First with a query lookup strategy, second with JPQL and third with native query.
Controller:
@RepositoryRestController
public class MyEntityController {
private final MyEntityRepository repository;
private final PagedService pagedService;
@Autowired
public MyEntityController(...) {...}
@GetMapping(value = "/my-entities/find/{value}")
@ResponseBody
public ResponseEntity<PagedModel<EntityModel<MyEntityProjection>>> find(@PathVariable String value,
Pageable pageable, PagedResourcesAssembler<MyEntityProjection> assembler) {
Page<MyEntityProjection> myEntities = findByMyField(value, pageable);
return pagedService.buildPagedResponse(myEntities, MyEntityProjection.class, assembler); // works
}
... findButWithQuery(...) {
Page<MyEntityProjection> myEntities = findByMyFieldButWithQuery(value, pageable);
return pagedService.buildPagedResponse(myEntities, MyEntityProjection.class, assembler); // throws error here
}
... findByMyFieldButWithNativeQuery(...) {
Page<MyEntityProjection> myEntities = findByMyFieldButWithNativeQuery(value, pageable);
return pagedService.buildPagedResponse(myEntities, MyEntityProjection.class, assembler); // throws error here
}
}
The controller has three endpoints where each one calls one of the queries. It then uses the following service to convert a Page<MyEntityProjection> into a ResponseEntity<PagedModel<EntityModel<MyEntityProjection>>>.
Service:
@Service
public class PagedService {
@SuppressWarnings("unchecked")
public <P> ResponseEntity<PagedModel<EntityModel<P>>> buildPagedResponse(Page<P> pagedEntities,
Class<P> projectionClazz, PagedResourcesAssembler<P> assembler) {
PagedModel<EntityModel<P>> model = null;
if (pagedEntities.isEmpty()) {
model = (PagedModel<EntityModel<P>>) assembler.toEmptyModel(pagedEntities, projectionClazz);
} else {
model = assembler.toModel(pagedEntities);
}
return (ResponseEntity<PagedModel<EntityModel<P>>>) new ResponseEntity<PagedModel<EntityModel<P>>>(model,
HttpStatus.OK);
}
}
The service is just a generic implementation that converts to the desired response format.
When the endpoint tries to return the response, Jackson throws a NullPointerException. I presume that the assembler didn't build the '_embedded' part of the response. Here's the error:
Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: (was java.lang.NullPointerException); nested exception is com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: org.springframework.hateoas.PagedModel["_embedded"]->java.util.LinkedHashMap["tupleBackedMaps"]->java.util.ArrayList[0]->org.springframework.hateoas.EntityModel["content"])]
Shouldn't this conversion when using JPQL and native queries work in a similar way to the query lookup strategy?
Comment From: wilkinsona
Spring Data REST is managed as a separate project and its runtime behaviour is really out of Spring Boot's control. As such, your question doesn't belong in the Spring Boot issue tracker. If you are looking for some guidance, please follow up on Stack Overflow or Gitter. If you believe that you have found a bug, please open a Spring Data REST issue.
Comment From: osnofa
Sorry, was not sure where to post the issue. I'll go to the Spring Data REST. Thanks.