1. 概述
在本教程中,我們將深入瞭解 Spring 的 HttpMessageNotWritableException: “No converter found for return value of type” 異常。
首先,我們將解釋該異常的主要原因。然後,我們將深入研究如何使用一個實際示例來生成該異常,最後將學習如何修復它。
2. 導致原因
通常,此異常發生時,Spring 無法獲取返回對象的屬性。
此異常的最常見原因通常是 返回對象沒有為其屬性提供公共的 Getter 方法。
Spring Boot 默認使用 Jackson 庫來處理請求和響應對象的序列化/反序列化任務。
因此,另一個 可能導致我們異常的原因是缺少或使用了錯誤的 Jackson 依賴項。
簡而言之,對於此類異常的一般指導是檢查以下內容:
- 默認構造函數
- Getter 方法
- 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]
最後,讓我們創建一個測試用例,以查看 Spring 在 getter 方法未定義時如何運行:
@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中返回的屬性定義一個獲取器方法。因此,讓我們在 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"));
}
一個不建議的解決方案是使屬性為公共,但是這種方法並不安全,因為它違背了許多最佳實踐。
5. 結論
在本文中,我們解釋了導致 Spring 拋出 org.springframework.http.converter.HttpMessageNotWritableException: “未找到轉換器用於返回類型” 的原因。
然後,我們討論瞭如何產生該異常以及如何在實踐中解決它。