TL;DR
Jackson
でnull
を特定の値にシリアライズする場合、以下の3つの方法が有ります1。
-
ObjectMapper
にシリアライザーを設定する -
JsonSerialize
アノテーションにシリアライザーを指定する - マッパー固有の方法で設定する
以下、それぞれの方法について書きます。
ここで、説明のためのシリアライザーとしては以下を用います。
このシリアライザーはnull
をn/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
だったプロパティ全てを同じように取り扱いたい場合に有効です。
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
全てを同じように取り扱いたい場合には向きません。
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
時に出力する値を設定することができます。