18

I'm trying to understand the exact behaviour of the Spring Data Rest Controllers.

I have made a simple implementation to test 4 kinds of annotated controllers: @BasePathAwareController, @RepositoryRestController, @RestController, @Controller

The controller has a mapping for an entity "author" in the repository.

This is the controller:

@BasePathAwareController
//@RepositoryRestController
//@RestController
//@Controller
public class MyController {

    @RequestMapping(value="authors/mycontroller/test")
    public void handleRequest(){
        System.out.println("handleRequest of class MyController");
    }

    @RequestMapping(value="/authors/mycontroller/testslash")
    public void handleSlashRequest(){
        System.out.println("handleSlashRequest of class MyController");
    }

    @RequestMapping(value="api/authors/mycontroller/test")
    public void handleApiRequest(){
        System.out.println("handleApiRequest of class MyController");
    }

    @RequestMapping(value="/api/authors/mycontroller/testslash")
    public void handleSlashApiRequest(){
        System.out.println("handleSlashApiRequest of class MyController");
    }

}

I'm testing 4 methods because I have some doubts about the right mapping to be used.

For every experiment, I use a different controller with the sames mappings, simply decommenting the annotation that I need for that experiment.

I'm calling these two URLS with HTTP GET:

http://localhost:8080/myApp/api/mycontroller/test
http://localhost:8080/myApp/api/mycontroller/testslash

This is the result that I obtain using @BasePathAwareController:

http://localhost:8080/myApp/api/mycontroller/test
    White page, No errors, No print on console

http://localhost:8080/myApp/api/mycontroller/testslash
    White page, No errors, No print on console

This is the result using @RepositoryRestController:

http://localhost:8080/myApp/api/mycontroller/test
    White page, No errors, No print on console

http://localhost:8080/myApp/api/mycontroller/testslash
    White page, and this message on the console (only for the first HTTP GET on this url):
    jul 27, 2016 9:23:57 AM org.springframework.web.servlet.DispatcherServlet noHandlerFound
    WARNING: No mapping found for HTTP request with URI [/myApp/api/authors/mycontroller/testslash] in DispatcherServlet with name 'rest'

This is the result if I use @RestController:

http://localhost:8080/myApp/api/mycontroller/test
    White page, in console: "handleRequest of class MyController"

http://localhost:8080/myApp/api/mycontroller/testslash
    White page, in console: "handleSlashRequest of class MyController"

Finally, this is the result using @Controller:

http://localhost:8080/myApp/api/mycontroller/test
    HTTP STATUS 404, in console: "handleRequest of class MyController"

http://localhost:8080/myApp/api/mycontroller/testslash
    HTTP STATUS 404, in console: "handleSlashRequest of class MyController"

For both urls I have this warning:

jul 27, 2016 9:28:11 AM org.springframework.web.servlet.DispatcherServlet noHandlerFound
WARNING: No mapping found for HTTP request with URI [/myApp/api/authors/mycontroller/authors/mycontroller/test] in DispatcherServlet with name 'rest'

I don't understand what's going on.

The only annotation that seems to provide the expected result is the @RestController.

@Controller apparently seems to work, but I have an HTTP status 404 and there is a message with an inconsistent URL /myApp/api/authors/mycontroller/authors/mycontroller/test, despite there is the correct handling message on the console.

The other two annotations (@BasePathAwareController and @RepositoryRestController) don't do nothing.

In summary:

  • @BasePathAwareController: doesn't do nothing
  • @RepositoryRestController: doesn't do nothing
  • @Controller: strange behaviour
  • @RestController: works perfectly

It would be greatly appreciated any type of clarification about the behaviour and the usage of every kind of @Controller.

Thanks.

Alessandro C
  • 3,310
  • 9
  • 46
  • 82

2 Answers2

9

I have found the way to make work all the annotated controllers, and I share it here.

@BasePathAwareController and @RepositoryRestController must have a @RequestMapping at class level:

@RepositoryRestController
//@BasePathAwareController
@RequestMapping(value="/authors/mycontroller")
public class MyController {

    @RequestMapping(value="/test")
    public void handleRequest(){
        //...
    }
}

Without the mapping at class level, both controllers are not handled.

That's the reason because in my previous tests the methods were never invoked.

The mapping at class level can starts with "/" or not, it works in both cases.

Furthermore, I have noticed that adding <mvc:default-servlet-handler/> in the configuration context, the warning "No mapping found for HTTP request with URI" is vanished.

Alessandro C
  • 3,310
  • 9
  • 46
  • 82
  • Please explain why the docs say "This controller (@RepositoryRestController) will be served from the same API base path defined in RepositoryRestConfiguration.setBasePath that is used by all other RESTful endpoints (e.g. /api)". And the code snippet DOES NOT have @RequestMapping on the class level. https://docs.spring.io/spring-data/rest/docs/3.0.1.RELEASE/reference/html/#customizing-sdr.overriding-sdr-response-handlers (chapter 15.4) – Błażej Kocik Nov 23 '17 at 04:43
  • wrong, they will be handled from the pluralized domain object class or from the path you specified in `RepositoryRestResource(path=` – Sam Jan 24 '18 at 16:26
  • It could depends by the version you are using. With the version I used in that time I solved in this way. – Alessandro C Jan 24 '18 at 18:03
  • 2
    I opened a spring-data-rest bug for this https://jira.spring.io/browse/DATAREST-1327 – Robert Dec 25 '18 at 20:50
  • 3
    I think the answer is already out of date for Spring Boot 2.5.6 "java.lang.IllegalStateException: Spring Data REST controller ... must not use @RequestMapping on class level as this would cause double registration with Spring MVC!" – Peters_ Nov 15 '21 at 13:19
  • @Peters_ yes, of course: this answer is right for Spring Boot 1; for newer versions it could be already solved by Spring developers. – Alessandro C Nov 15 '21 at 18:34
-3

As you are using a REST API you need to use @RestController

For further reading check out the spring docs.

UserF40
  • 3,533
  • 2
  • 23
  • 34
  • 1
    Thanks for your answer. But in what conditions is supposed to be used the other ones? – Alessandro C Jul 27 '16 at 08:26
  • 1
    I have already read the documentation... If I'm here it's because I have a different result despite what is written in the documentation. – Alessandro C Jul 27 '16 at 08:34
  • Be careful when overriding Spring data rest repository partially with a controller. You should not use class level mapping. https://jira.spring.io/browse/DATAREST-535 – Akash Aug 09 '18 at 01:00