1. 概要

この簡単な記事では、 Jacksonを使用するより高度なユースケースを見ていきます–null値またはnullキーを含むマップを操作します。

2. マップ内のヌル値を無視する

Jacksonには、マップがシリアル化されたときにnull値に何が起こるかをグローバルに制御するシンプルで便利な方法があります。

ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(Include.NON_NULL);

これで、このマッパーを介してシリアル化されたMapオブジェクトのnull値は無視されます。

@Test
public void givenIgnoringNullValuesInMap_whenWritingMapObjectWithNullValue_thenIgnored() 
  throws JsonProcessingException {
    ObjectMapper mapper = new ObjectMapper();
    mapper.setSerializationInclusion(Include.NON_NULL);

    MyDto dtoObject1 = new MyDto();

    Map<String, MyDto> dtoMap = new HashMap<String, MyDto>();
    dtoMap.put("dtoObject1", dtoObject1);
    dtoMap.put("dtoObject2", null);

    String dtoMapAsString = mapper.writeValueAsString(dtoMap);

    assertThat(dtoMapAsString, containsString("dtoObject1"));
    assertThat(dtoMapAsString, not(containsString("dtoObject2")));
}

3. ヌルキーを使用したマップのシリアル化

デフォルトでは、Jacksonはnullキーを使用したマップのシリアル化を許可していません。 このようなマップを書き出そうとすると、次の例外が発生します。

c.f.j.c.JsonGenerationException: 
  Null key for a Map not allowed in JSON (use a converting NullKeySerializer?)
    at c.f.j.d.s.i.FailingSerializer.serialize(FailingSerializer.java:36)

ただし、ライブラリは十分な柔軟性を備えているため、カスタムのヌルキーシリアライザーを定義し、デフォルトの動作をオーバーライドできます。

class MyDtoNullKeySerializer extends StdSerializer<Object> {
    public MyDtoNullKeySerializer() {
        this(null);
    }

    public MyDtoNullKeySerializer(Class<Object> t) {
        super(t);
    }
    
    @Override
    public void serialize(Object nullKey, JsonGenerator jsonGenerator, SerializerProvider unused) 
      throws IOException, JsonProcessingException {
        jsonGenerator.writeFieldName("");
    }
}

これで、nullキーを使用したマップが正常に機能し、nullキーは空の文字列として書き込まれます。

@Test
public void givenAllowingMapObjectWithNullKey_whenWriting_thenCorrect() 
throws JsonProcessingException {
    ObjectMapper mapper = new ObjectMapper();
    mapper.getSerializerProvider().setNullKeySerializer(new MyDtoNullKeySerializer());

    MyDto dtoObject = new MyDto();
    dtoObject.setStringValue("dtoObjectString");
 
    Map<String, MyDto> dtoMap = new HashMap<String, MyDto>();
    dtoMap.put(null, dtoObject);

    String dtoMapAsString = mapper.writeValueAsString(dtoMap);

    assertThat(dtoMapAsString, containsString("\"\""));
    assertThat(dtoMapAsString, containsString("dtoObjectString"));
}

4. ヌルフィールドを無視する

マップに加えて、Jacksonは、一般にnullフィールドを無視/操作するための多くの構成と柔軟性を提供します。 このチュートリアルをチェックして、それがどのように機能するかを正確に確認できます。

5. 結論

Mapオブジェクトのシリアル化は十分に一般的であるため、シリアル化プロセスの微妙な違いをうまく処理できるライブラリが必要です。 Jacksonは、このシリアル化プロセスの出力を非常にうまく形作るのに役立ついくつかの便利なカスタマイズオプションを提供します。

また、より一般的な意味でコレクションを操作するための多くの確実な方法を提供します。

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