Generic Top

Get started with Spring 5 and Spring Boot 2, through the Learn Spring course:

>> CHECK OUT THE COURSE

1. Overview

In this short article, we're going to take a close look at the Spring exception, “HttpMessageNotWritableException: no converter for [class …] with preset Content-Type”.

First, we'll shed light on the main cause behind the exception. Then, we'll go down the rabbit hole to see how to reproduce it using a practical example and, finally, how to solve it.

2. The Cause

Before diving deep into the details, let's try to understand what the exception means.

The stack trace of the exception says it all: It tells us that Spring fails to find a suitable HttpMessageConverter capable of converting a Java object into the HTTP response.

Basically, Spring relies on the “Accept” header to detect the media type that it needs to respond with.

So, using a media type with no pre-registered message converter will cause Spring to fail with the exception.

3. Reproducing the Exception

Now that we know what causes Spring to throw our exception, let's see how to reproduce it using a practical example.

Let's create a handler method and pretend to specify a media type (for the response) that has no registered HttpMessageConverter.

For instance, let's use APPLICATION_XML_VALUE or “application/xml”:

@GetMapping(value = "/student/v3/{id}", produces = MediaType.APPLICATION_XML_VALUE)
public ResponseEntity<Student> getV3(@PathVariable("id") int id) {
    return ResponseEntity.ok(new Student(id, "Robert", "Miller", "BB"));
}

Next, let's send a request to http://localhost:8080/api/student/v3/1 and see what happens:

curl http://localhost:8080/api/student/v3/1

The endpoint sends back this response:

{"timestamp":"2022-02-01T18:23:37.490+00:00","status":500,"error":"Internal Server Error","path":"/api/student/v3/1"}

Indeed, looking at the logs, Spring fails with the HttpMessageNotWritableException exception:

[org.springframework.http.converter.HttpMessageNotWritableException: No converter for [class com.baeldung.boot.noconverterfound.model.Student] with preset Content-Type 'null']

So, the exception is thrown because there is no HttpMessageConverter capable of marshaling and unmarshaling Student objects to and from XML.

Finally, let's create a test case to confirm that Spring throws HttpMessageNotWritableException with the specified message:

@Test
public void whenConverterNotFound_thenThrowException() throws Exception {
    String url = "/api/student/v3/1";

    this.mockMvc.perform(get(url))
      .andExpect(status().isInternalServerError())
      .andExpect(result -> assertThat(result.getResolvedException()).isInstanceOf(HttpMessageNotWritableException.class))
      .andExpect(result -> assertThat(result.getResolvedException()
        .getMessage()).contains("No converter for [class com.baeldung.boot.noconverterfound.model.Student] with preset Content-Type"));
}

4. The Solution

There's only one way to fix the exception – to use a media type that has a registered message converter.

Spring Boot relies on auto-configuration to register the built-in message converters.

For example, it will register MappingJackson2HttpMessageConverter automatically if the Jackson 2 dependency is present in the classpath.

With that being said, and knowing that Spring Boot includes Jackson in the web starter, let's create a new endpoint with the APPLICATION_JSON_VALUE media type:

@GetMapping(value = "/student/v2/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Student> getV2(@PathVariable("id") int id) {
    return ResponseEntity.ok(new Student(id, "Kevin", "Cruyff", "AA"));
}

Now, let's create a test case to confirm that everything works as excepted:

@Test
public void whenJsonConverterIsFound_thenReturnResponse() throws Exception {
    String url = "/api/student/v2/1";

    this.mockMvc.perform(get(url))
      .andExpect(status().isOk())
      .andExpect(content().json("{'id':1,'firstName':'Kevin','lastName':'Cruyff', 'grade':'AA'}"));
}

As we can see, Spring does not throw HttpMessageNotWritableException, thanks to MappingJackson2HttpMessageConverter, which handles the conversion of the Student object to JSON under the hood.

5. Conclusion

In this short tutorial, we discussed in detail what causes Spring to throw “HttpMessageNotWritableException No converter for [class …] with preset Content-Type”.

Along the way, we showcased how to produce the exception and how to fix it in practice.

As always, the full source code of the examples is available over on GitHub.

Generic bottom

Get started with Spring 5 and Spring Boot 2, through the Learn Spring course:

>> CHECK OUT THE COURSE
Generic footer banner
4 Comments
Oldest
Newest
Inline Feedbacks
View all comments
Comments are closed on this article!