HttpMessageNotWritableException:未找到類型返回值的轉換器

    1.概述

    在本教程中,我們將闡明Spring的HttpMessageNotWritableException: “No converter found for return value of type”異常。

    首先,我們將解釋導致異常的主要原因。然後,我們將進行更深入的研究,以了解如何使用實際示例來製作它,以及最後如何修復它。

    2.原因

    通常,當Spring無法獲取返回對象的屬性時,將發生此異常。

    導致此異常的最典型原因通常是,返回的對象的屬性沒有任何公共的getter方法

    默認情況下,Spring Boot依靠Jackson庫來完成所有序列化/反序列化請求和響應對象的繁重工作。

    因此,導致我們異常的另一個常見原因可能是缺少或使用了錯誤的Jackson依賴項

    簡而言之,此類例外的一般準則是檢查是否存在以下情況:

    • 默認構造函數
    • Getters方法
    • Jackson依賴

    請記住, 異常類型已從java.lang.IllegalArgumentException更改為org.springframework.http.converter.HttpMessageNotWritableException.

    3.實際例子

    現在,讓我們看一個生成org.springframework.http.converter.HttpMessageNotWritableException的示例:“未找到類型返回值的轉換器”。

    為了演示真實的用例,我們將使用Spring Boot構建一個用於學生管理的基本REST API。

    首先,讓我們創建模型類Student並假裝忘記生成getter方法

    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控制器,以按其id Student對象:

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

    現在,如果我們使用CURL http://localhost:8080/api/student/1

    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]

    最後,讓我們創建一個測試用例,以查看未在Student類中定義getter方法時Spring的行為:

    @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.解決方案

    防止異常的最常見解決方案之一是為我們要以JSON返回的每個對象的屬性定義一個getter方法。

    因此,讓我們在Student類中添加getter方法並創建一個新的測試用例,以驗證一切是否都能按預期工作:

    @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: ” No converter found for return value of type”

    然後,我們討論瞭如何產生異常以及如何在實踐中解決該異常。