1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Jackson】AnnotationIntrospectorでJsonGetter同様の動作を実現する

Posted at

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 {}

やり方

以下のようにすることで実装できます。

  1. AnnotationIntrospectorを実装する1
  2. 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}(プロパティの順番は不同?)が出力されます。
ここではSimpleModuleObjectMapperに登録する形で書いています。

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に対するfindCreatorAnnotationJsonAnyGetterに対するhasAnyGetterというように、アノテーションを付与したのと同じ挙動を実現するためのメソッドが用意されている場合も有ります。

一方、JsonGetterに対してはそのようなメソッドが用意されていませんでした。
そこでJackson側のコードを見た所、JacksonAnnotationIntrospectorに実装が有りました。

この記事は上記コードを参考に書いています。

  1. NopAnnotationIntrospectorをベースにしているのは、Jackson側で指定が有るためです。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?