TL;DR
-
AnnotationIntrospector
にはJsonGetter
同様の動作を再現するための明示的なメソッドは用意されていない -
findNameForSerialization
を実装することで、JsonGetter
同様の動作を実現できる
本文
JsonGetterとは
Jackson
では、名前がgetter
に当たるメソッドしかシリアライズ対象になりません。
一方、JsonGetter
アノテーションを付与したメソッドは名前に関わらずシリアライズ対象となります。
// シリアライズすると{"foo":1,"bar":2}が出力される
class Src {
public int getFoo() { return 1; }
@JsonGetter public int bar() { return 2; }
}
やりたいこと
Jackson
の挙動をカスタムして、特定条件でJsonGetter
同様の動作をさせます。
今回は以下のMyAnnotation
が設定されていたメソッドであることを条件にします。
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {}
やり方
以下のようにすることで実装できます。
-
AnnotationIntrospector
を実装する1 -
findNameForSerialization
で、条件に一致していれば値を返すようにする
以下は実装のサンプルです。
import com.fasterxml.jackson.databind.PropertyName;
import com.fasterxml.jackson.databind.introspect.Annotated;
import com.fasterxml.jackson.databind.introspect.NopAnnotationIntrospector;
public class MyAnnotationIntrospector extends NopAnnotationIntrospector {
@Override
public PropertyName findNameForSerialization(Annotated a) {
return _findAnnotation(a, MyAnnotation.class) != null ? PropertyName.USE_DEFAULT : null;
}
}
使い方
以下をシリアライズしてみます。
import com.fasterxml.jackson.annotation.JsonGetter;
class Src {
public int getFoo() { return 1; }
@JsonGetter public int bar() { return 2; }
@MyAnnotation public int baz() { return 3; }
}
以下のmain
関数を実行すると、{"baz":3,"foo":1,"bar":2}
(プロパティの順番は不同?)が出力されます。
ここではSimpleModule
をObjectMapper
に登録する形で書いています。
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
public class Main {
public static void main(String[] args) throws JsonProcessingException {
SimpleModule simpleModule = new SimpleModule() {
@Override
public void setupModule(Module.SetupContext context) {
super.setupModule(context);
context.appendAnnotationIntrospector(new MyAnnotationIntrospector());
}
};
ObjectMapper mapper = JsonMapper.builder()
.addModule(simpleModule)
.build();
Src src = new Src();
System.out.println(mapper.writeValueAsString(src));
}
}
補足
アノテーションや特定名・クラスを条件に挙動をカスタムする場合、AnnotationIntrospector
を実装することになります。
このクラスには、JsonCreator
に対するfindCreatorAnnotation
、JsonAnyGetter
に対するhasAnyGetter
というように、アノテーションを付与したのと同じ挙動を実現するためのメソッドが用意されている場合も有ります。
一方、JsonGetter
に対してはそのようなメソッドが用意されていませんでした。
そこでJackson
側のコードを見た所、JacksonAnnotationIntrospector
に実装が有りました。
この記事は上記コードを参考に書いています。
-
NopAnnotationIntrospector
をベースにしているのは、Jackson
側で指定が有るためです。 ↩