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:
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
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.
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.
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
}
}