Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I'm writing a servlet that will use a bunch of RestControllers to provide functionality.

All of that will use JSON almost exclusively, so I would like a compact way to say: Unless specified otherwise, consume and produce MediaType.APPLICATION_JSON_VALUE for everything.

I thought I found a nice solution on another SO question .

However, as already pointed out in a comment there , this solution causes trouble.

@RestController
@RequestMapping(value = "/relationship/type", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE, method = {
        RequestMethod.GET
public class DRelationshipTypeResource {
    // @GetMapping("/all")
    @RequestMapping(value = "/all", method = RequestMethod.GET)
    public List<DRelationshipTypeDTO> getAll() {
        return DRelationshipTypeService.getAll();

This controller also will feature POST/PUT/DELETE plus some more GETs. I removed them for now to minimize possible causes of errors.

Calling this route produces a 415 error.

Even worse, I would really like to be able to use

@GetMapping("/all")

instead of the more verbose @RequestMapping Overload for the getAll()-Method, but that also produces the same 415 error.

Server debug console spits out this when the request arrives:

2019-01-29 10:20:54.627  WARN 10712 --- [io-9999-exec-10] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content type '' not supported]
2019-01-29 10:20:54.628 ERROR 10712 --- [io-9999-exec-10] o.a.c.c.C.[Tomcat].[localhost]           : Exception Processing ErrorPage[errorCode=0, location=/error]
java.lang.NoSuchMethodError: javax.servlet.http.HttpServletRequest.getHttpServletMapping()Ljavax/servlet/http/HttpServletMapping;
    at org.apache.catalina.core.ApplicationHttpRequest.setRequest(ApplicationHttpRequest.java:690) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.catalina.core.ApplicationHttpRequest.<init>(ApplicationHttpRequest.java:114) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.catalina.core.ApplicationDispatcher.wrapRequest(ApplicationDispatcher.java:917) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:358) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:312) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.catalina.core.StandardHostValve.custom(StandardHostValve.java:394) [tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.catalina.core.StandardHostValve.status(StandardHostValve.java:253) [tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:175) [tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) [tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) [tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) [tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834) [tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1417) [tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.14.jar:9.0.14]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_181]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_181]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.14.jar:9.0.14]
    at java.lang.Thread.run(Thread.java:748) [na:1.8.0_181]

and returns a HTTP Status 415 – Unsupported Media Type to the client making the request.

To clarify further, if I use a "dumb" class such as this, everything works fine, with the content correctly being returned as JSON.

@RestController
@RequestMapping("relationship/type")
public class DRelationshipTypeResource {
    @GetMapping("/all")
    public List<DRelationshipTypeDTO> getAll() {
        return DRelationshipTypeService.getAll();
                Check your message converter, and check this answer stackoverflow.com/questions/54400807/…
– Narendra Pandey
                Jan 28, 2019 at 16:53
                I updated the OP to clarify things. Thanks for the inquiries! As the content is returned correctly with the code sample above, I don't think the JSON conversion itself is the issue.
– Senshi
                Jan 29, 2019 at 9:32
                Can you please add the details on how your making call? And client that your using for the testing. And also add the complete stack trace of the error
– Hareesh
                Jan 29, 2019 at 9:53
                Tested clients are Postman and browsers (tested IE, Firefox, Chrome) with a plain call to localhost:9999/api/relationship/type/all . Not sure what else you need? Above is the complete stacktrace, there is nothing else logged when calling the route.
– Senshi
                Jan 29, 2019 at 10:01

As the stack trace, clearly telling content-type is empty (' '). I think Content-Type is not passed while making the GET call. If you pass Content-Type as 'application/json' it should work.

You have defined consumes and produces at the class level, which means by default all the REST services should pass headers, Content-Type and Accept in order to consume the service.

Solution was to add "Content-Type" header. The Accept was irrelevant (tried that before). I was switching from JaxRS, which is very similar in its setup, but JaxRS doesn't complain about missing headers, it simply provides the first that is defined in "produces" if no content-type header is present. Thanks for the help. – Senshi Jan 29, 2019 at 10:19

It's missing to add / at beginning on your path and add method type GET:

@RequestMapping(value = "/relationship/type", 
                consumes = MediaType.APPLICATION_JSON_VALUE, 
                produces = MediaType.APPLICATION_JSON_VALUE,
                method = {RequestMethod.GET}))
                Thanks for the comment. The "/" in the beginning is not required (it works just fine without), but for consistency's sake I should add it, I agree there. Adding the method to the RequestMapping above did not change the response in any way or shape, sadly, I still get the same stacktrace and the 415 error.
– Senshi
                Jan 29, 2019 at 9:32
                To add: Having the method types on the class-level RequestMapping has no impact either way. It works just fine without them.
– Senshi
                Jan 29, 2019 at 10:42

To accept all request type just overwrite consumes value.

@RequestMapping(value = "/all", consumes="*/*", method = RequestMethod.GET)
    public List<DRelationshipTypeDTO> getAll() {
        return DRelationshipTypeService.getAll();

The issue was with my requests not explicitly having a Content-Type application/json header, as pointed out by https://stackoverflow.com/a/54418436/2436002 .

To clear up some of the apparent misinformation about all this, everything worked just as I expected now, with very readable, clean and spring-like code. Maybe it can help others looking for an example.

@RestController
@RequestMapping(value = "relationship/type", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public class DRelationshipTypeResource {
    @GetMapping("/all")
    public List<DRelationshipTypeDTO> getAll() {
        return DRelationshipTypeService.getAll();
    @GetMapping("/{query}")
    public DRelationshipTypeDTO get(@PathVariable("query") String query) {
        return DRelationshipTypeService.get(query);
    @PostMapping
    public ResponseEntity<Void> create(DRelationshipTypeDTO dto) {
        String label = DRelationshipTypeService.create(dto);
        URI uri = ServletUriComponentsBuilder.fromCurrentRequest().path("/{label}").buildAndExpand(label).toUri();
        return ResponseEntity.created(uri).build();
    @PutMapping("{label}")
    public ResponseEntity<Void> update(@PathVariable("label") String label, DRelationshipTypeDTO dto) {
        DRelationshipTypeService.update(label, dto);
        return ResponseEntity.noContent().build();
    @DeleteMapping("{label}")
    public ResponseEntity<Void> delete(@PathVariable("label") String label) {
        DRelationshipTypeService.delete(label);
        return ResponseEntity.noContent().build();

Not 100% yet on the best method for URI-Building during the POST /Create, but that's a different issue, and it at least works fine (proper location header for HTTP201 response).

Thanks a lot. I didn't find anywhere else you could use RequestMapping on the controller class itself – Olav Kokovkin Mar 19, 2022 at 11:21

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.