LoginSignup
1
0

More than 1 year has passed since last update.

【Jackson】nullを特定の値にシリアライズする3通りの方法

Last updated at Posted at 2022-09-25

TL;DR

Jacksonnullを特定の値にシリアライズする場合、以下の3つの方法が有ります1

  1. ObjectMapperにシリアライザーを設定する
  2. JsonSerializeアノテーションにシリアライザーを指定する
  3. マッパー固有の方法で設定する

以下、それぞれの方法について書きます。
ここで、説明のためのシリアライザーとしては以下を用います。
このシリアライザーはnulln/aという文字列にシリアライズします。

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;

import java.io.IOException;

public class MyNullValueSerializer extends JsonSerializer<Object> {
    @Override
    public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        if (value != null) throw new RuntimeException("このシリアライザーはnull以外の値を処理できません");

        gen.writeString("n/a");
    }
}

また、この記事ではJava 16/Jackson 2.13.4を利用しています。

ObjectMapperにシリアライザーを設定する

まず、ObjectMapper.getSerializerProvider().setNullValueSerializerで、ObjectMapperにシリアライザーを設定する方法です。
この方法は特にnullだったプロパティ全てを同じように取り扱いたい場合に有効です。

ObjectMapperにシリアライザーを設定するサンプル
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class ToObjectMapper {
    private static final ObjectMapper mapper;

    static {
        mapper = new ObjectMapper();
        mapper.getSerializerProvider().setNullValueSerializer(new MyNullValueSerializer());
    }

    public static void main(String[] args) throws JsonProcessingException {
        Src src = new Src(null, "bar");
        System.out.println(mapper.writeValueAsString(src));
    }
}
実行結果
{"foo":"n/a","bar":"bar"}

シリアライズ対象クラスには以下のようなクラスを用いる想定です2

public record Src(String foo, String bar) {}

対象を特定の型に限定したい場合

上記の方法は、nullだった際の扱いが全ての型に適用されてしまうという欠点が有ります。
適用する型を絞りたい場合、適切に実装したAnnotationIntrospectorを登録する方法が有ります。

以下は対象となる型Stringに絞ったAnnotationIntrospectorです。

import com.fasterxml.jackson.databind.introspect.Annotated;
import com.fasterxml.jackson.databind.introspect.NopAnnotationIntrospector;

public class MyAnnotationIntrospector extends NopAnnotationIntrospector {
    @Override
    public Object findNullSerializer(Annotated am) {
        if (am.getRawType() == String.class) {
            return new MyNullValueSerializer();
        }

        return null;
    }
}

登録方法は以下の通りです。

    static {
        mapper = new ObjectMapper();
+       mapper.setAnnotationIntrospector(new MyAnnotationIntrospector());
-       mapper.getSerializerProvider().setNullValueSerializer(new MyNullValueSerializer());
    }

JsonSerializeアノテーションにシリアライザーを指定する

次に、JsonSerializeアノテーションのnullsUsingにシリアライザーを指定する方法です。
この方法は特定プロパティがnullだった場合の挙動を設定する際に有効ですが、一々アノテーションを設定する必要が有るため、null全てを同じように取り扱いたい場合には向きません。

JsonSerializeアノテーションにシリアライザーを指定するサンプル
import com.fasterxml.jackson.databind.annotation.JsonSerialize;

public record Src(@JsonSerialize(nullsUsing = MyNullValueSerializer.class) String foo, String bar) {}
呼び出しサンプル
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class ToAnnotation {
    private static final ObjectMapper mapper = new ObjectMapper();

    public static void main(String[] args) throws JsonProcessingException {
        Src src = new Src(null, null);
        System.out.println(mapper.writeValueAsString(src));
    }
}

実行結果からは、JsonSerializeアノテーションの設定の有無でシリアライズ結果が異なっていることが分かります。

実行結果
{"foo":"n/a","bar":null}

マッパー固有の方法で設定する

Jacksonでは、jackson-dataformats-textとして様々なフォーマットのファイルに関する取り扱いがサポートされており、これらの中にはnullを特定の値にシリアライズする独自の方法が提供されているものが有ります。

例えば、jackson-dataformat-csvのシリアライズに用いられるCsvSchemaは、Builderから初期化する場合、null時に出力する値を設定することができます。

  1. 自分が把握している限りです。

  2. 断りなくrecord classを使っていますが、説明の大筋には関係無いので言及はしません。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0