[java] Spring MVC + JSON = 406 Not Acceptable

I'm trying to generate a simple JSON response working. Right now I get 406 Not Acceptable error. Tomcat says "The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers." even though my Accept headers are

Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

In tomcat/lib I have all Tomcat jars, Spring jars and jackson-all-1.9.0.jar. I'm using Spring 3.2.2 with Tomcat 7.

I'm aware that this issue has been discussed many times, but none of solutions is working for me.

web.xml

<web-app id="WebApp_ID" version="2.4" 
    xmlns="http://java.sun.com/xml/ns/j2ee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

  <display-name>Spring Web MVC Application</display-name>

  <servlet>
    <servlet-name>dispatcher</servlet-name>
        <servlet-class>
                  org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
        <url-pattern>*.htm</url-pattern>
  </servlet-mapping>

</web-app>

dispatcher-servlet.xml

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
     http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver" >
        <property name="prefix">
            <value>/WEB-INF/pages/</value>
        </property>
        <property name="suffix">
            <value>.jsp</value>
        </property>
    </bean>
 <context:component-scan base-package="com.smiechmateusz.controller" />
 <context:annotation-config />

    <mvc:annotation-driven />

</beans>

HelloWorldController.java

package com.smiechmateusz.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;

import com.smiechmateusz.dao.Foo;

@Controller
@RequestMapping("/")
public class HelloWorldController extends AbstractController{

    @Override
    protected ModelAndView handleRequestInternal(HttpServletRequest request,
        HttpServletResponse response) throws Exception {

        ModelAndView model = new ModelAndView("HelloWorldPage");
        return model;
    }

    @RequestMapping(value="foobar.htm", method = RequestMethod.GET)
    public @ResponseBody Foo getShopInJSON() {
        Foo f = new Foo();
        f.setX(1);
        f.setY(2);
        f.setDescription("desc");
        return f;
    }
}

Foo.java

package com.smiechmateusz.dao;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="foobaz")
public class Foo implements Serializable
{
    private int x, y;
    String description;
    int id;

    @Column(name = "x")
    public int getX() {
        return x;
    }
    public void setX(int x) {
        this.x = x;
    }
    @Column(name = "y")
    public int getY() {
        return y;
    }
    public void setY(int y) {
        this.y = y;
    }
    @Column(name = "description")
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }

    @Id @GeneratedValue
    @Column(name = "id")
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
}

I've already tried adding

<bean id="jsonConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <property name="messageConverters">
          <list>
            <ref bean="jsonConverter"/>
          </list>
    </property>
</bean>

to my dispatcher-servlet.xml or changing jakcson-all to jackson-asl and jackson-core-asl but output was the same.

This question is related to java json spring

The answer is


There is another case where this status will be returned: if the Jackson mapper cannot figure out how to serialize your bean. For example, if you have two accessor methods for the same boolean property, isFoo() and getFoo().

removed getFoo() and put isFoo(). it worked for me.


I suppose, that the problem was in usage of *.htm extension in RequestMapping (foobar.htm). Try to change it to footer.json or something else.

The link to the correct answer: https://stackoverflow.com/a/21236862/537246

P.S.

It is in manner of Spring to do something by default, concerning, that developers know whole API of Spring from A to Z. And then just "406 not acceptable" without any details, and Tomcat's logs are empty!


this is because of the object is not acceptable at jsp... use his

add this dependency or any other send converted json string to jsp...

for example add this in pom

<dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.6.2</version>
    </dependency>

and use code like that:

@RequestMapping(value="foobar.htm", method = RequestMethod.GET)
    public @ResponseBody String getShopInJSON() {
        Foo f = new Foo();
        f.setX(1);
        f.setY(2);
        f.setDescription("desc");
        return new Gson().toJson(f); //converted object into json string
    }//return converted json string

Maybe all fields of your POJO need Getter and Setter.

I fixed it according to this issue. reference:Spring MVC - HttpMediaTypeNotAcceptableException

And 406 is not a useful message to fix the bug. You should debug into the codes and see what the Exception is on earth.


As it is the top answer for this error, I am adding the case for XML here.

There is also a possibility that the object returned hasn't correctly defined XML structure. That was the case for me.

public @ResponseBody DataObject getData(

Was throwing the same error despite correct headers. The errors stopped when I added @XmlRootElement to the header of the object:

@XmlRootElement
public class DataObject {
    @XmlElement(name = "field", nillable = true)
    protected String field;

Use below dependency in your pom

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.5.3</version>
</dependency>

If you're using Maven and the latest Jackson code then you can remove all the Jackson-specific configuration from your spring configuration XML files (you'll still need an annotation-driven tag <mvc:annotation-driven/>) and simply add some Jackson dependencies to your pom.xml file. See below for an example of the dependencies. This worked for me and I'm using:

  • Apache Maven 3.0.4 (r1232337; 2012-01-17 01:44:56-0700)
  • org.springframework version 3.1.2.RELEASE
  • spring-security version 3.1.0.RELEASE.

    ...<dependencies>
    ...
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.2.3</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.2.3</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.2.3</version>
        </dependency>
        ...
    </dependencies>...
    

None of the other answers helped me.

I read dozens of Stackoverflow answers about 406 Not Acceptable, HttpMediaTypeNotAcceptableException, multipart file, ResponseBody, setting Accept headers, produces, consumes etc.

We had Spring 4.2.4 with SpringBoot and Jackson configured in build.gradle:

compile "com.fasterxml.jackson.core:jackson-core:2.6.7"
compile "com.fasterxml.jackson.core:jackson-databind:2.6.7"

All routes worked fine in our other controllers and we could use GET, POST, PUT, and DELETE. Then I started to add multipart file upload capability and created a new controller. The GET routes work fine but our POST and DELETE didn't. No matter how I tried different solutions from here at SO I just kept getting 406 Not Acceptable.

Then finally I stumbled across this SO answer: Spring throwing HttpMediaTypeNotAcceptableException: Could not find acceptable representation due to dot in url path

Read Raniz's answer and all the comments.

It all boiled down to our @RequestMapping values:

@RequestMapping(value = "/audio/{fileName:.+}", method = RequestMethod.POST, consumes="multipart/*")
public AudioFileDto insertAudio(@PathVariable String fileName, @RequestParam("audiofile") MultipartFile audiofile) {

    return audioService.insert(fileName, audiofile);
}

@RequestMapping(value = "/audio/{fileName:.+}", method = RequestMethod.DELETE)
public Boolean deleteAudio(@PathVariable String fileName) {

    return audioService.remove(fileName);
}

The {fileName:.+} part in a @RequestMapping value caused the 406 Not Acceptable in our case.

Here's the code I added from Raniz's answer:

@Configuration
public class ContentNegotiationConfig extends WebMvcConfigurerAdapter {
    @Override
    void configureContentNegotiation(final ContentNegotiationConfigurer configurer) {
        // Turn off suffix-based content negotiation
        configurer.favorPathExtension(false);
    }
}

EDIT August 29th 2016:

We got into trouble using configurer.favorPathExtension(false): static SVG images ceased to load. After analysis, we found that Spring started to send SVG files back to UI with content-type "application/octet-stream" instead of "image/svg+xml". We solved this by sending fileName as a query parameter, like:

@RequestMapping(value = "/audio", method = RequestMethod.DELETE)
public Boolean deleteAudio(@RequestParam String fileName) {

    return audioService.remove(fileName);
}

We also removed the configurer.favorPathExtension(false). Another way could be to encode fileName in the path but we chose the query parameter method to avoid further side effects.


See the problem is with the extension. Depending upon the extension, spring could figure out the content-type. If your url ends with .com then it sends text/html as the content-type header. If you want to change this behavior of Spring, please use the below code:

@Configuration
@Import(HibernateConfig.class)
@EnableWebMvc
// @EnableAsync()
// @EnableAspectJAutoProxy
@ComponentScan(basePackages = "com.azim.web.service.*",  basePackageClasses = { WebSecurityConfig.class }, excludeFilters = { @ComponentScan.Filter(Configuration.class) })
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer.favorPathExtension(false).favorParameter(true).parameterName("mediaType").ignoreAcceptHeader(true).useJaf(false)
                .defaultContentType(MediaType.APPLICATION_JSON).mediaType("xml", MediaType.APPLICATION_XML).mediaType("json", MediaType.APPLICATION_JSON);
    }

    @Bean(name = "validator")
    public Validator validator() {
        return new LocalValidatorFactoryBean();
    }
}

Here, we are setting favorPathExtension to false and Default Content-type to Application/json. Note: HibernateConfig class contains all the beans.


I had the same issue, in my case the following was missing from my xxx-servlet.xml config file

<mvc:annotation-driven/>

As soon I added this it it worked.


You have to register the annotation binding for Jackson in your spring-mvc-config.xml, for example :

<!-- activates annotation driven binding -->
<mvc:annotation-driven ignoreDefaultModelOnRedirect="true" validator="validator">
    <mvc:message-converters>
        <bean class="org.springframework.http.converter.ResourceHttpMessageConverter"/>
        <bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter"/>
        <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>
    </mvc:message-converters>
</mvc:annotation-driven>

Then in your controller you can use :

@RequestMapping(value = "/your_url", method = RequestMethod.GET, produces = "application/json")
@ResponseBody

One more way you can get this error is to create a class with no public members. 406 unacceptable is a pretty useless error message in this scenario.


It looks like your are trying to produce/recieve json output. I see two problems with your approach. 1) You didn't specify the application/json in your Accept header 2) You need to specify produces="application/json" in your @RequestMapping


My class was annotated with JsonSerialize, and the include parameter was set to JsonSerialize.Inclusion.NON_DEFAULT. This caused Jackson to determine the default values for each bean property. I had a bean property that returned an int. The problem in my case was that the bean getter made a call to a method which has an inferred return type (i.e.: a generic method). For some odd reason this code compiled; it shouldn't have compiled because you cannot use an int for an inferred return type. I changed the 'int' to an 'Integer' for that bean property and I no longer got a 406. The odd thing is, the code now fails to compile if I change the Integer back to an int.


Try adding

@RequestMapping(method = RequestMethod.GET,headers = {"Accept=text/xml, application/json"})

on getShopInJSON().

It worked for me.


I couldn't see it as an answer here so I thought I would mention that I recieved this error using spring 4.2 when I accidentally removed the getter/setter for the class I was expecting to be returned as Json.


I have got the similar issue and resolved by using below code

public class ProductList {

    private List<Product> productList =  new ArrayList<Product>();

    @JsonProperty("data")
    @JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.WRAPPER_OBJECT)
    public List<Product> getProductList() {
        return productList;
    }
public void setProductList(List<Product> productList) {
        this.productList = productList;
    }

I am setting ProductList object in ResponseEntity object and returning from controller.

My RequestMapping value was ending with .html which should be something different.

I tried changing it to .json and it worked for me.


Today I too gone through the same issue. In my case, in web.xml I have

   <servlet-mapping>
        <servlet-name>spring</servlet-name>
        <url-pattern>*.html</url-pattern>
    </servlet-mapping>

my url is having .html extension. Ex:.../getUsers.html. But I am returning JSON data in controller. .html extension will by default set accept type as html.

So I changed to the following:

web.xml:

<servlet-mapping>
    <servlet-name>spring</servlet-name>
    <url-pattern>*.html</url-pattern>
    <url-pattern>*.json</url-pattern>
</servlet-mapping>

URL:

.../getUsers.json

Everything is working fine now. Hope it helps.


With Spring 4 you only add @EnableWebMvc, for example:

@Controller
@EnableWebMvc
@RequestMapping(value = "/articles/action", headers="Accept=*/*",  produces="application/json")
public class ArticlesController {

}

Examples related to java

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How much should a function trust another function How to implement a simple scenario the OO way Two constructors How do I get some variable from another class in Java? this in equals method How to split a string in two and store it in a field How to do perspective fixing? String index out of range: 4 My eclipse won't open, i download the bundle pack it keeps saying error log

Examples related to json

Use NSInteger as array index Uncaught SyntaxError: Unexpected end of JSON input at JSON.parse (<anonymous>) HTTP POST with Json on Body - Flutter/Dart Importing json file in TypeScript json.decoder.JSONDecodeError: Extra data: line 2 column 1 (char 190) Angular 5 Service to read local .json file How to import JSON File into a TypeScript file? Use Async/Await with Axios in React.js Uncaught SyntaxError: Unexpected token u in JSON at position 0 how to remove json object key and value.?

Examples related to spring

Are all Spring Framework Java Configuration injection examples buggy? Two Page Login with Spring Security 3.2.x Access blocked by CORS policy: Response to preflight request doesn't pass access control check Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean Failed to auto-configure a DataSource: 'spring.datasource.url' is not specified Spring Data JPA findOne() change to Optional how to use this? After Spring Boot 2.0 migration: jdbcUrl is required with driverClassName The type WebMvcConfigurerAdapter is deprecated No converter found capable of converting from type to type