Tiberiu
Tiberiu

Reputation: 1030

No suitable HttpMessageConverter for content type application/json;charset=UTF-8

I am getting the exception in the title, even after adding all the code found online in other solutions (I've added the HttpMessageConverters as well as the APPLICATION_JSON accept header.)

public MyObject myMethod(String arg) {
    String uri = BASE_URI + "/var?arg=" + arg;

    restTemplate.setMessageConverters(getMessageConverters());

    HttpHeaders headers = new HttpHeaders();
    headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
    HttpEntity<String> entity = new HttpEntity<>(headers);

    ResponseEntity<MyObject> response = restTemplate.exchange(uri, HttpMethod.GET, entity, MyObject.class);
    MyObject resource = response.getBody();

    return resource;

}

private List<HttpMessageConverter<?>> getMessageConverters() {
    List<HttpMessageConverter<?>> converters =
            new ArrayList<>();
    converters.add(new MappingJackson2HttpMessageConverter());
    converters.add(new StringHttpMessageConverter(Charset.forName("UTF-8")));
    return converters;
}

MyObject:

public class MyObject {

    private String test;
    //more fields

    @JsonCreator
    public MyObject(String test) { //more args
        this.test = test;
        //more assignments
    }

Anyone have any idea?

EDIT: relevant dependencies in pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-integration</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.9.8</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.8</version>
</dependency>

Upvotes: 0

Views: 10524

Answers (2)

Ananthapadmanabhan
Ananthapadmanabhan

Reputation: 6216

By default spring or springboot configures the following message converters during startup :

ByteArrayHttpMessageConverter – converts byte arrays
StringHttpMessageConverter – converts Strings
ResourceHttpMessageConverter – converts org.springframework.core.io.Resource for any type of octet stream
SourceHttpMessageConverter – converts javax.xml.transform.Source
FormHttpMessageConverter – converts form data to/from a MultiValueMap<String, String>.
Jaxb2RootElementHttpMessageConverter – converts Java objects to/from XML
MappingJackson2HttpMessageConverter – converts JSON
MappingJacksonHttpMessageConverter – converts JSON
AtomFeedHttpMessageConverter – converts Atom feeds 
RssChannelHttpMessageConverter – converts RSS feeds

But for the Jackson converters to be added , spring has to detect that jackson is present in the classpath, so by adding jackson dependency to your application,the converter should be automatically configured, unless you are explicitly preventing the auto configuration by using the @EnableWebMVC annotation.

Also,ensure that if you are using a rest endpoint, the method is annotated correctly, that is either use @RestController for the class or else you will have to provide the @ResponseBody annotation to indicate spring that it is a rest endpoint.

From the documentation:

Annotation indicating a method parameter should be bound to the body of the web request. The body of the request is passed through an HttpMessageConverter to resolve the method argument depending on the content type of the request. Optionally, automatic validation can be applied by annotating the argument with @Valid. Supported for annotated handler methods in Servlet environments.

Upvotes: 2

Lesiak
Lesiak

Reputation: 25936

Note that for the HttpMessageConverter to be eligible for mapping, it's canRead method must return true.

In the case of AbstractJackson2HttpMessageConverter (parent of MappingJackson2HttpMessageConverter), it checks not only MediaType, but also if Jackson can deserialize the object.

@Override
public boolean canRead(Type type, @Nullable Class<?> contextClass, @Nullable MediaType mediaType) {
    if (!canRead(mediaType)) {
        return false;
    }
    JavaType javaType = getJavaType(type, contextClass);
    AtomicReference<Throwable> causeRef = new AtomicReference<>();
    if (this.objectMapper.canDeserialize(javaType, causeRef)) {
        return true;
    }
    logWarningIfNecessary(javaType, causeRef.get());
    return false;
}

Now, I believe your JsonCreator is incorrect.

NOTE: when annotating creator methods (constructors, factory methods), method must either be:

  • Single-argument constructor/factory method without JsonProperty annotation for the argument: if so, this is so-called "delegate creator", in which case Jackson first binds JSON into type of the argument, and then calls creator. This is often used in conjunction with JsonValue (used for serialization).
  • Constructor/factory method where every argument is annotated with either JsonProperty or JacksonInject, to indicate name of property to bind to

See also Why when a constructor is annotated with @JsonCreator, its arguments must be annotated with @JsonProperty?

Upvotes: 0

Related Questions