Spring Data REST: Override repository method on the controller

Nicolas picture Nicolas · Apr 21, 2016 · Viewed 21k times · Source

I have the following REST repository, whose implementation is generated at runtime by Spring.

@RepositoryRestResource
public interface FooRepository extends CrudRepository<Foo, Long> {

}

This means that I will have save(), find(), exists() and other methods available and exposed via REST.

Now, I would like to override one of the methods; for example, save(). For that, I would create a controller exposing that method, like so:

@RepositoryRestController
@RequestMapping("/foo")
public class FooController {

    @Autowired
    FooService fooService;


    @RequestMapping(value = "/{fooId}", method = RequestMethod.PUT)
    public void updateFoo(@PathVariable Long fooId) {
        fooService.updateProperly(fooId);
    }

}

The problem: If I enable this controller, then all of the other methods implemented by Spring are not exposed anymore. So, for example, I can no longer do a GET request to /foo/1

Question: Is there a way of overriding REST methods while still keeping the other auto-generated Spring methods?

Extra info:

  1. This question seems very similar: Spring Data Rest: Override Method in RestController with same request-mapping-path ... but I don't want to change the path to something like /foo/1/save

  2. I thought of using a @RepositoryEventHandler but I'm not very fond of that idea because I would like to encapsulate it under a service. Also, you seem to lose control of the transaction context.

  3. This part of the Spring Data documentation says the following:

    Sometimes you may want to write a custom handler for a specific resource. To take advantage of Spring Data REST’s settings, message converters, exception handling, and more, use the @RepositoryRestController annotation instead of a standard Spring MVC @Controller or @RestController

so it seems that it should work out of the box, but unfortunately not.

Answer

Marc Tarin picture Marc Tarin · Apr 22, 2016

Is there a way of overriding REST methods while still keeping the other auto-generated Spring methods?

Look at the example in the documentation carefully: while not explicitly forbidding class-level requestmapping, it uses method-level requestmapping. I'm not sure if this is the wanted behavior or a bug, but as far as I know this is the only way to make it work, as stated here.

Just change your controller to:

@RepositoryRestController
public class FooController {

    @Autowired
    FooService fooService;

    @RequestMapping(value = "/foo/{fooId}", method = RequestMethod.PUT)
    public void updateFoo(@PathVariable Long fooId) {
        fooService.updateProperly(fooId);
    }

    // edited after Sergey's comment
    @RequestMapping(value = "/foo/{fooId}", method = RequestMethod.PUT)
    public RequestEntity<Void> updateFoo(@PathVariable Long fooId) {
        fooService.updateProperly(fooId);

        return ResponseEntity.ok().build(); // simplest use of a ResponseEntity
    }
}