简体   繁体   中英

Content type 'application/json' not supported in Spring MVC and jackson

I'm getting an error (Handler execution resulted in exception: Content type 'application/json' not supported) when trying to receive a post request using Spring MVC.

My Json, just for testing, is pretty simple:

{ "test": "abc123" }

My pojo class:

public class Request {

    String test;

    public String getTest() {
        return test;
    }

    public void setTest(String test) {
        this.test = test;
    }

}

And my controller:

@RequestMapping(value = "/testing", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
private void testing(@RequestBody Request body, @RequestHeader HttpHeaders headers, HttpServletRequest httpRequest) {
    System.out.println(body.getTest());
}

In my pom.xml, I added:

<dependencies>
    ...
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.7.2</version>
    </dependency>
    <dependency>
        <groupId>org.codehaus.jackson</groupId>
        <artifactId>jackson-mapper-asl</artifactId>
        <version>1.8.5</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.dataformat</groupId>
        <artifactId>jackson-dataformat-xml</artifactId>
        <version>2.4.3</version>
    </dependency>
</dependencies>

I think that something is wrong in json deserialization, but I cannot find it.

Any help is welcome. Thanks.

Here is my working example:

@SpringBootApplication
@Controller
public class Application {

  public static void main(String[] args) {
    SpringApplication.run(Application.class);
  }


  @RequestMapping(value = "/testing", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
  @ResponseBody
  private void testing(@RequestBody Request body, @RequestHeader HttpHeaders headers, HttpServletRequest httpRequest) {
    System.out.println(body.getTest());
  }
}

This project has only 1 dependency:

org.springframework.boot:spring-boot-starter-web

When I call the url like this:

curl -XPOST -v -d '{ "test": "abc123" }' -H "Content-type: application/json" http://localhost:8080/testing

I see the correct abc123 in the logs. If I remove Content-type header I get the exception

org.springframework.web.HttpMediaTypeNotSupportedException","message":"Content type 'application/x-www-form-urlencoded' not supported

In my case the problem was an addition to a dto of a property which having a type that was error prone for Jackson, it was of type JsonObject. Jackson was unable to deserialize other objects because of that addition.
The exception message is completely inaccurate!

Add this Bean in your webconfig class

@Bean
public ContentNegotiatingViewResolver contentViewResolver() {
    ContentNegotiationManagerFactoryBean contentNegotiationManager = new ContentNegotiationManagerFactoryBean();
    contentNegotiationManager.addMediaType("json", MediaType.APPLICATION_JSON);

    InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
    viewResolver.setPrefix("/WEB-INF/jsp/");
    viewResolver.setSuffix(".jsp");

    MappingJackson2JsonView defaultView = new MappingJackson2JsonView();
    defaultView.setExtractValueFromSingleKeyModel(true);

    ContentNegotiatingViewResolver contentViewResolver = new ContentNegotiatingViewResolver();
    contentViewResolver.setContentNegotiationManager(contentNegotiationManager.getObject());
    contentViewResolver.setViewResolvers(Arrays.<ViewResolver> asList(viewResolver));
    contentViewResolver.setDefaultViews(Arrays.<View> asList(defaultView));
    return contentViewResolver;
}

UPDATE

The guys from the comments are right, this won't fix your issue but I noticed something.

If I set consumes = MediaType.APPLICATION_JSON_VALUE and in the request I don't specify the content type it will throw an exception then if I set the content type the issue is fixed.

Now, the issue seems to be something with your dependencies.

My pom dependencies:

 <properties>
     <springframework.version>4.1.9.RELEASE</springframework.version>
     <springframework.security.oauth.version>2.0.9.RELEASE</springframework.security.oauth.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

    ...

</properties>

<dependencies>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
        <version>${springframework.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>${springframework.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>${springframework.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${springframework.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.security.oauth</groupId>
        <artifactId>spring-security-oauth2</artifactId>
        <version>${springframework.security.oauth.version}</version>
    </dependency>

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

    ...

</dependencies>

对于寻找此问题的其他任何人,我的Pojo类上必须至少有一个公共变量或吸气剂。

I had same issue. finally i resolved it. Actual error was in jackson lib. Here is the location and code snippet.

/* \.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.6.5\jackson-databind-2.6.5-sources.jar!\com\fasterxml\jackson\databind\DeserializationContext.java  406 */


public boolean hasValueDeserializerFor(JavaType type, AtomicReference<Throwable> cause) {
        try {
            return _cache.hasValueDeserializerFor(this, _factory, type);
        } catch (JsonMappingException e) {
            if (cause != null) {
                cause.set(e);
            }
        } catch (RuntimeException e) {
            if (cause == null) { // earlier behavior
                throw e;
            }
            cause.set(e);
        }
        return false;
    }

For those who use Spring Framework , not Spring Boot, and encounter this problem.

The root of this problem is:

  • Spring need to ① recognize the "Content-Type", and ② convert the content to the parameter type we declared in the method's signature.

  • The ' application/json ' is not supported, because, by default , the Spring cannot find a proper HttpMessageConverter to do the converting job , which is step ②.

Solution :

  • We manually add a proper HttpMessageConverter into the Spring's configuration of our application .

Steps:

  1. Choose the HttpMessageConverter's class we want to use. For Json, we can choose from "org.springframework.http.converter.json. JsonbHttpMessageConverter ", "org.springframework.http.converter.json. MappingJackson2HttpMessageConverter ", and so on .

  2. Add the JsonbHttpMessageConverter object (or other kinds of Json HttpMessageConverter object ) to Spring's configuration , by calling the "public void configureMessageConverters (List<HttpMessageConverter<?>> converters)" method of the "WebMvcConfigurer" implementation class in our application. Inside the method, we can add any HttpMessageConverter object as needed, by using " converters.add() ".

  3. Add correspond dependency into "pom.xml" file. For example, if you use the " JsonbHttpMessageConverter ", then you need to add the dependencies of " javax.json.bind-api " and " yasson ".

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM