I have a Spring Data REST project. For some URLs I want to create a @Controller that renders the resources as HTML. I am using a @RequestMapping with produces = MediaType.TEXT_HTML_VALUE. In fact this controller is called if the URL is requested. However, if I do a request for JSON I get a 406 - while in fact the Spring Data REST controller should be called. I noticed that the log output says that the Spring Data REST controller doesn't register with any value for produces.
I think a value for produces should be given. Maybe there is a way to do this but I didn't find it in the reference documentation. Maybe there are other ways to get different representations of the REST resources but that doesn't seem to be documented either. I guess different representations for the same resource are an important part of REST so I think there should be a way to do what I want to do
Affects: 2.2.2 (Evans SR2), 2.3 RC1 (Fowler)
DATAREST-522 GET on RestRepository not possible, if a RestController for the same path is available
The issue is not so much the Spring Data REST controllers not defining any produces attribute but our custom HandlerMapping setup: we currently register two HandlerMapping instances: one that handles all controllers annotated with @BasePathAwareController which are controllers whose mappings have to honor the Spring Data REST base-path configuration (e.g. the ones serving ALPS metadata). The second handler mapping handles all controllers that expose resources for repositories.
The split is necessary as the latter handling applies a stricter check for mappings to make sure it's not actually trying to handle requests for paths that are not backed by repositories. In a standard Spring MVC application, this setup will even be prepended with a standard RequestMappingHandlerMapping that will cause all standard Spring MVC controllers to be handled.
Depending on whether you use @BasePathAwareController or @Controller in your scenario, Spring MVC detects the the mapping bound to text/html as content type but rightfully not consider it as its produces clause does not match. org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping.handleNoMatch(…) will then discover the request actually matching except the media type and thus throw an exception to indicate that state. This however bubbles up through DispatcherServlet.getHandler(…) which actually iterates all HandlerMapping to find a suitable ones but thus causes all other registered HandlerMapping instances not even being tried.
IYAM, that particular method should actually continue trying to resolve a handler until it exhausted all registered and only throw the exception if it couldn't find one eventually. Although I haven't made up my mind on which exception to finally throw in case multiple HandlerMappings threw exceptions. As this would mean a pretty core change to the framework, I wonder what juergen.hoeller and Rossen Stoyanchev think about this.
The even more problematic aspect here is that we can't fully solve this issue in Spring Data REST. I could of course hide our two HandlerMapping implementations behind a delegating HandlerMapping that does the special exception handling. This however would not fix the issue for users using @Controller as this would still be handled by a separate HandlerMapping and thus run into the issue described above
This should be fixed with this commit. I basically implemented what I described above, so that you should be able to get this working using @BasePathAwareController. Discovered a [tiny glitch|SPR-12806] in DispatcherServlet along the way.
Feel free to give the 2.3.0 snapshots a try (switching the Spring Boot spring-data-releasetrain.version property to Fowler-BUILD-SNAPSHOT