Рубрики
Без рубрики

“HttpMessageNotWritableException: Не найден конвертер для возвращаемого значения типа”

Автор оригинала: Abderrahim Azhrioun.

1. Обзор

В этом уроке мы прольем свет на исключение Spring HttpMessageNotWritableException: “Не найден конвертер для возвращаемого значения типа” исключение.

Во-первых, мы объясним основные причины исключения. Затем мы копнем глубже, чтобы увидеть, как создать его на примере реального мира, и, наконец, как его исправить.

2. Причины

Как правило, это исключение возникает, когда Spring не удается извлечь свойства возвращаемого объекта.

Наиболее типичной причиной этого исключения обычно является то, что возвращаемый объект не имеет никаких общедоступных методов получения для своих свойств .

По умолчанию Spring Boot полагается на библиотеку Джексона для выполнения всей тяжелой работы по сериализации/десериализации объектов запросов и ответов.

Таким образом, другой распространенной причиной нашего исключения может быть отсутствие или использование неправильных зависимостей Джексона .

Короче говоря, общее руководство для такого исключения состоит в том, чтобы проверить наличие:

  • Конструктор по умолчанию
  • Добытчики
  • Зависимости Джексона

Пожалуйста, имейте в виду, что тип исключения изменился с java.lang.IllegalArgumentException to org.springframework.http.converter.HttpMessageNotWritableException.

3. Практический Пример

3. Практический Пример

Чтобы продемонстрировать реальный пример использования, мы собираемся создать базовый REST API для управления студентами с помощью Spring Boot .

Во-первых, давайте создадим наш класс модели Студент и сделаем вид, что забыли сгенерировать методы геттера :

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
}

Во-вторых, мы создадим контроллер Spring с одним методом обработчика для извлечения объекта Student по его id :

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

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

Теперь, если мы отправим запрос на http://localhost:8080/api/student/1 использование CURL :

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

Конечная точка отправит обратно этот ответ:

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

Глядя на журналы, Spring выбросил исключение HttpMessageNotWritableException :

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

Наконец, давайте создадим тестовый случай, чтобы увидеть, как Spring ведет себя, когда методы getter не определены в классе Student :

@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. Решение

Одним из наиболее распространенных решений для предотвращения исключения является определение метода getter для каждого свойства объекта, которое мы хотим вернуть в JSON.

Итак, давайте добавим методы getter в класс Student и создадим новый тестовый случай, чтобы проверить, все ли будет работать так, как ожидалось:

@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"));
}

Опрометчивым решением было бы обнародование свойств. Однако это не на 100% безопасный подход, поскольку он противоречит нескольким лучшим практикам.

5. Заключение

В этой короткой статье мы объяснили, что заставляет Spring выбрасывать org.springframework.http.converter.HttpMessageNotWritableException: “Не найден конвертер для возвращаемого значения типа” .

Затем мы обсудили, как создать исключение и как его устранить на практике.

Как всегда, полный исходный код примеров доступен на GitHub .