1. 概要

このチュートリアルでは、Springの HttpMessageNotWritableException:「タイプの戻り値のコンバーターが見つかりません」例外に光を当てます。

まず、例外の主な原因について説明します。 次に、実際の例を使用してそれを作成する方法と、最後にそれを修正する方法をさらに深く掘り下げます。

2. 原因

通常、この例外は、Springが返されたオブジェクトのプロパティのフェッチに失敗した場合に発生します。

この例外の最も一般的な原因は、通常、返されたオブジェクトにそのプロパティのパブリックゲッターメソッドがないことです。

デフォルトでは、SpringBootはJacksonライブラリに依存して、要求および応答オブジェクトのシリアル化/逆シリアル化のすべての面倒な作業を行います。

したがって、例外の別の一般的な原因が欠落しているか、間違ったJackson依存関係を使用している可能性があります。

要するに、そのような例外の一般的なガイドラインは、以下の存在をチェックすることです。

  • デフォルトのコンストラクタ
  • ゲッター
  • ジャクソンの依存関係

例外タイプjava.lang.IllegalArgumentExceptionからorg.springframework.http.converter.HttpMessageNotWritableException。に変更されたことに注意してください。

3. 実例

ここで、org.springframework.http.converter.HttpMessageNotWritableExceptionを生成する例を見てみましょう。「タイプの戻り値のコンバーターが見つかりません」。

実際のユースケースを示すために、Spring Bootを使用して学生管理用の基本的なRESTAPIを構築します。

まず、モデルクラス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
}

次に、idによってStudentオブジェクトを取得するために、単一のハンドラーメソッドを使用してSpringコントローラーを作成します。

@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. ソリューション

例外を防ぐための最も一般的な解決策の1つは、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% safeアプローチではありません。

5. 結論

この短い記事では、Springが org.springframework.http.converter.HttpMessageNotWritableExceptionをスローする原因について説明しました:「タイプの戻り値のコンバーターが見つかりません」

次に、例外を生成する方法と実際にそれに対処する方法について説明しました。

いつものように、例の完全なソースコードは、GitHubから入手できます。