1. 概要

このクイックチュートリアルでは、ゲッターのないエンティティのマーシャリングとJacksonJsonMappingException例外の解決策を分析します。

より深く掘り下げてジャクソン2でできる他のクールなことを学びたい場合は、メインのジャクソンチュートリアルに進んでください。

2. 問題

デフォルトでは、Jackson 2は、パブリックまたはパブリックゲッターメソッドを持つフィールドでのみ機能します。すべてのフィールドがプライベートまたはパッケージプライベートであるエンティティのシリアル化は失敗します

public class MyDtoNoAccessors {
    String stringValue;
    int intValue;
    boolean booleanValue;

    public MyDtoNoAccessors() {
        super();
    }

    // no getters
}
@Test(expected = JsonMappingException.class)
public void givenObjectHasNoAccessors_whenSerializing_thenException() 
  throws JsonParseException, IOException {
    String dtoAsString = new ObjectMapper().writeValueAsString(new MyDtoNoAccessors());

    assertThat(dtoAsString, notNullValue());
}

完全な例外は次のとおりです。

com.fasterxml.jackson.databind.JsonMappingException: 
No serializer found for class dtos.MyDtoNoAccessors 
and no properties discovered to create BeanSerializer 
(to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) )

3. ソリューション

明らかな解決策は、エンティティが私たちの管理下にある場合、フィールドにゲッターを追加することです。 そうではなく、エンティティのソースを変更できない場合、Jacksonはいくつかの選択肢を提供します。

3.1. 可視性のあるフィールドをグローバルに自動検出

この問題の最初の解決策は、 ObjectMapper をグローバルに構成して、可視性に関係なく、すべてのフィールドを検出することです。

objectMapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);

これにより、プライベートフィールドとパッケージプライベートフィールドをゲッターなしで検出できるようになり、シリアル化が正しく機能します。

@Test
public void givenObjectHasNoAccessors_whenSerializingWithAllFieldsDetected_thenNoException() 
  throws JsonParseException, IOException {
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
    String dtoAsString = objectMapper.writeValueAsString(new MyDtoNoAccessors());

    assertThat(dtoAsString, containsString("intValue"));
    assertThat(dtoAsString, containsString("stringValue"));
    assertThat(dtoAsString, containsString("booleanValue"));
}

3.2. クラスレベルですべてのフィールドを検出

Jackson 2が提供するもう1つのオプションは、グローバル構成の代わりに、@JsonAutoDetectアノテーションを介してクラスレベルでフィールドの可視性を制御することです。

@JsonAutoDetect(fieldVisibility = Visibility.ANY)
public class MyDtoNoAccessors { ... }

このアノテーションを使用すると、シリアル化はこの特定のクラスで正しく機能するはずです。

@Test
public void givenObjectHasNoAccessorsButHasVisibleFields_whenSerializing_thenNoException() 
  throws JsonParseException, IOException {
    ObjectMapper objectMapper = new ObjectMapper();
    String dtoAsString = objectMapper.writeValueAsString(new MyDtoNoAccessors());

    assertThat(dtoAsString, containsString("intValue"));
    assertThat(dtoAsString, containsString("stringValue"));
    assertThat(dtoAsString, containsString("booleanValue"));
}

4. 結論

この記事では、 ObjectMapper または個々のクラスのいずれかでカスタム可視性をグローバルに構成することにより、Jacksonのデフォルトのフィールド可視性を回避する方法を説明しました。 ジャクソンは、特定の可視性を持つゲッター、セッター、またはフィールドがマッパーによってどのように表示されるかを正確に制御するオプションを提供することにより、さらにカスタマイズを可能にします。

これらすべての例とコードスニペットの実装は、私のGitHubプロジェクトにあります。これはEclipseベースのプロジェクトであるため、そのままインポートして実行するのは簡単です。