Can I make a custom controller mirror the formatting of Spring-Data-Rest / Spring-Hateoas generated classes?

spring, spring-data, spring-data-rest, spring-hateoas, spring-mvc

Solution

I've found a way to imitate the behavior of Spring Data Rest completely. The trick lies in using a combination of the `PagedResourcesAssembler` and an argument-injected instance of `PersistentEntityResourceAssembler`. Simply define your controller as follows...

@RepositoryRestController
@RequestMapping("...")
public class ThingController {

    @Autowired
    private PagedResourcesAssembler pagedResourcesAssembler;

    @SuppressWarnings("unchecked") // optional - ignores warning on return statement below...
    @RequestMapping(value = "...", method = RequestMethod.GET)
    @ResponseBody
    public PagedResources<PersistentEntityResource> customMethod(
            ...,
            Pageable pageable,
            // this gets automatically injected by Spring...
            PersistentEntityResourceAssembler resourceAssembler) {

        Page<MyEntity> page = ...;
        ...
        return pagedResourcesAssembler.toResource(page, resourceAssembler);
    }
}

This works thanks to the existence of `PersistentEntityResourceAssemblerArgumentResolver`, which Spring uses to inject the `PersistentEntityResourceAssembler` for you. The result is exactly what you'd expect from one of your repository query methods!

Problem

I'm trying to do something I think should be really simple. I have a `Question` object, setup with spring-boot, spring-data-rest and spring-hateoas. All the basics work fine. I would like to add a custom controller that returns a `List<Question>` in exactly the same format that a GET to my `Repository`'s `/questions` url does, so that the responses between the two are compatible. Here is my controller: ``` @Controller public class QuestionListController { @Autowired private QuestionRepository questionRepository; @Autowired private PagedResourcesAssembler<Question> pagedResourcesAssembler; @Autowired private QuestionResourceAssembler questionResourceAssembler; @RequestMapping( value = "/api/questions/filter", method = RequestMethod.GET, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) public @ResponseBody PagedResources<QuestionResource> filter( @RequestParam(value = "filter", required = false) String filter, Pageable p) { // Using queryDSL here to get a paged list of Questions Page<Question> page = questionRepository.findAll( QuestionPredicate.findWithFilter(filter), p); // Option 1 - default resource assembler return pagedResourcesAssembler.toResource(page); // Option 2 - custom resource assembler return pagedResourcesAssembler.toResource(page, questionResourceAssembler); } } ``` Option 1: Rely on the provided `SimplePagedResourceAssembler` The problem with this option is none of the necessary `_links` are rendered. If there was a fix for this, it would be the easiest solution. Option 2: Implement my open resource assembler The problem with this option is that implementing `QuestionResourceAssembler` according to the Spring-Hateoas documentation leads down a path where the `QuestionResource` ends up being a near-duplicate of `Question`, and then the assembler needs to manually copy data between the two objects, and I need to build all the relevant `_links` by hand. This seems like a lot of wasted effort. What to do? I know Spring has already generated the code to do all this when it exports the `QuestionRepository`. Is there any way I can tap into that code and use it, to ensure the output from my controller is seamless and interchangeable with the generated responses?

Original source

Related problems