1. Overview

In this tutorial, we’re going to shed light on Spring’s HttpMessageNotWritableException: “No converter found for return value of type” exception.

First, we’ll explain the main causes of the exception. Then, we’ll dig deeper to see how to produce it using a real-world example and finally how to fix it.

2. The Causes

Typically, this exception occurs when Spring fails to fetch the properties of a returned object.

The most typical cause of this exception is usually that the returned object doesn’t have any public getter methods for its properties.

By default, Spring Boot relies on the Jackson library to do all the heavy lifting of serializing/deserializing request and response objects.

So, another common cause of our exception could be missing or using the wrong Jackson dependencies.

In short, the general guideline for such an exception is to check for the presence of:

  • Default constructor
  • Getters
  • Jackson dependencies

Please bear in mind that the exception type has changed from java.lang.IllegalArgumentException to org.springframework.http.converter.HttpMessageNotWritableException.

3. Practical Example

Now, let’s see an example that generates org.springframework.http.converter.HttpMessageNotWritableException: “No converter found for return value of type”.

To demonstrate a real-world use case, we’re going to build a basic REST API for student management using Spring Boot.

Firstly, let’s create our model class Student and pretend to forget to generate the getter methods:

public class Student {

    private int id;
    private String firstName;
    private String lastName;
    private String grade;

    public Student() {
    }

    public Student(int id, String firstName, String lastName, String grade) {
    this.id = id;
    this.firstName = firstName;
    this.lastName = lastName;
    this.grade = grade;
    }

    // Setters
}

Secondary, we’ll create a Spring controller with a single handler method to retrieve a Student object by its id:

@RestController
@RequestMapping(value = "/api")
public class StudentRestController {

    @GetMapping("/student/{id}")
    public ResponseEntity<Student> get(@PathVariable("id") int id) {
        // Custom logic
        return ResponseEntity.ok(new Student(id, "John", "Wiliams", "AA"));
     }
}

Now, if we send a request to http://localhost:8080/api/student/1 using CURL:

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

The endpoint will send back this response:

{"timestamp":"2021-02-14T14:54:19.426+00:00","status":500,"error":"Internal Server Error","message":"","path":"/api/student/1"}

Looking at the logs, Spring threw the HttpMessageNotWritableException:

[org.springframework.http.converter.HttpMessageNotWritableException: No converter found for return value of type: class com.baeldung.boot.noconverterfound.model.Student]

Finally, let’s create a test case to see how Spring behaves when the getter methods are not defined in the Student class:

@RunWith(SpringRunner.class)
@WebMvcTest(StudentRestController.class)
public class NoConverterFoundIntegrationTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void whenGettersNotDefined_thenThrowException() throws Exception {

        String url = "/api/student/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 found for return value of type"));
    }
}

4. The Solution

One of the most common solutions to prevent the exception is to define a getter method for each object’s property we want to return in JSON.

So, let’s add the getter methods in the Student class and create a new test case to verify if everything will work as expected:

@Test
public void whenGettersAreDefined_thenReturnObject() throws Exception {

    String url = "/api/student/2";

    this.mockMvc.perform(get(url))
      .andExpect(status().isOk())
      .andExpect(jsonPath("$.firstName").value("John"));
}

An ill-advised solution would be making the properties public. However, this is not a 100% safe approach as it goes against several best practices.

5. Conclusion

In this short article, we explained what causes Spring to throw org.springframework.http.converter.HttpMessageNotWritableException: ” No converter found for return value of type”.

Then, we discussed how to produce the exception and how to address it in practice.

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