Saturday, 18 February 2017

Spring MVC 406 Not Acceptable JSON Error Tutorial

How to fix 406 Not Acceptable error with Spring Ajax Json


This is a very simple yet frustrating problem with Spring MVC webapp and AJAX call w/ JSON request/response. The error that is thrown is "406 Not Acceptable".



What are we trying to do and getting the error?
Basically we need to send ResponseBody from Spring controller to our JSP page using AJAX get call. Simple Enough..!!
If we are sending a primitive response (like String, Integer etc) this it will be working without any issue.

But, if you are trying to send an Object or a List or a Map and expecting Spring to automatically convert them into JSON and send as response, you are getting this fucked up error 406.


Solution
Well the internet is full of answers to this solution. And yes when i faced this issue, i probably tried most of it but when i land at the very last Stack Overflow answer, I was like WTF.

Some of the solutions are-
1. missing in dispatcher servlet.
This is absolutely not needed.
All you need is mvn namespace marked dispatcher servlet.

2. Missing Jackson dependencies - Yes you need but which one.
I found some saying codehaus and other saying fasterxml and some saying both.
But you just need to add 1 dependency as below

          com.fasterxml.jackson.core
          jackson-databind
          2.8.6

Spring needs above dependency to perform the conversion of Java object to JSON

3. Add in RequestMapping(path="/list", method=RequestMethod.GET) below
produces="application/json"
headers="Accept=*/*"
Both are not needed

4. Check if the class you are returning in a collection or directly has getters and setters.
Yes this is very important. You class should have POJOs and also it should be completely initialized.
In my case, I was getting the list from hibernate and thus it was not initialized completely due to lazy loading feature of hibernate.

5. contentType missing in my ajax call.
This is important if you are using $.ajax to send the call. You can use a better json version where its not needed but if you are using $.ajax then it is important.
Something like
$.ajax({
    type: "GET",
    contentType: "application/json",
    url: "/type.do",
    data: "id=" + categoryVal,
    success: function(response) {
        alert(response);
    }
})

6. @EnableWebMvc annotation missing on my controller. - Yes this is important and must be present.

7. Finally the problem i was facing. Make sure that the URL pattern does not contain list.html or list.htm (i mean .html or .htm) as URL pattern.
Why this can be a problem?
With htm or html, the server is going to use content negotiation first before checking the value of Accept header. With an extension like *.htm, Spring will use a org.springframework.web.accept.ServletPathExtensionContentNegotiationStrategy and resolve that the acceptable media type to return is text/html which does not match what MappingJacksonHttpMessageConverter produces, ie. application/json and therefore a 406 is returned.

The simple solution is to add "*.do" url pattern in web.xml
The complicated solution is to change the order of the ContentNegotiationStrategy objects registered with the RequestResponseBodyMethodProcessor which handles your @ResponseBody.

Note: Make sure you are aware of curl to test the call. It is very handy.
curl -i -H "Accept: application/json" http://localhost:8080/type.do?id=51 -X GET

Visit Here where I found the Solution.

1 comment :