web-dev-qa-db-ja.com

ジャクソンマッパーポストコンストラクト

Jackson ObjectMapperを使用してJSONをJavaクラスに逆シリアル化します。これをPlayerDataと呼びます。ロジックを少し追加したいと思います。 PlayerDataクラスに追加して、フィールドが読み込まれた後に一部のデータを修正します。たとえば、初期のJSONファイルの中には、「性別」フラグではなく「性別」フラグを使用していたものがあります。が設定されているが、性別フラグが設定されていないので、性別フィールドの値を性別フィールドの値に設定したいと思います。

メソッドに付けることができる@PostConstructまたは@AfterLoadアノテーションのようなものはありますか?それとも私が実装できるインターフェースですか?ドキュメントで気づかなかったのですが、明らかな機能のようでした。

31

コメントで リンク を介してこれを見つけました(クレジット: fedor.belov )。これにより、コードポストコンストラクトを実行できるようになります。

http://jira.codehaus.org/browse/JACKSON-645 または http://jira.codehaus.org/browse/JACKSON -538 そして、デシリアライザーが完了した後に呼び出されるメソッドを探しています。アノテーションを含め、入出力と同じクラスを使用するコンバーターを作成することで、目的の効果を得ることができました。

@JsonDeserialize(converter=MyClassSanitizer.class)  // invoked after class is fully deserialized
public class MyClass {
    public String field1;
}

import com.fasterxml.jackson.databind.util.StdConverter;
public class MyClassSanitizer extends StdConverter<MyClass,MyClass> {
  @Override
  public MyClass convert(MyClass var1) {
    var1.field1 = munge(var1.field1);
    return var1;
  }
}
16
Mike Rylander

@JsonCreatorを使用していない場合、Jacksonはsetterメソッドとgetterメソッドを使用してフィールドを設定します。

したがって、SexGenderの列挙型があると仮定して、次のメソッドを定義すると、次のようになります。

@JsonProperty("sex")
public void setSex(final Sex sex) {
  this.sex = sex;
  if (gender == null) {
    gender = (sex == Sex.WOMAN) ? Gender.WOMAN : Gender.MAN;
  }
}

@JsonProperty("gender")
public void setGender(final Gender gender) {
  this.gender = gender;
  if (sex == null) {
    sex = (gender == Gender.WOMAN) ? Sex.WOMAN : Sex.MAN;
  }
}

それはうまくいくでしょう。

Update:Jacksonライブラリのすべての注釈を見つけることができます ここ

Update2:その他の解決策:

class Example {
  private final Sex sex;
  private final Gender gender;

  @JsonCreator
  public Example(@JsonProperty("sex") final Sex sex) {
    super();
    this.sex = sex;
    this.gender = getGenderBySex(sex)
  }

  @JsonFactory
  public static Example createExample(@JsonProperty("gender") final Gender gender) {
    return new Example(getSexByGender(gender));
  }

  private static Sex getSexByGender(final Gender) {
    return (gender == Gender.WOMAN) ? Sex.WOMAN : Sex.MAN;
  }

  private static Gender getGenderBySex(final Sex) {
    return (sex == Sex.WOMAN) ? Gender.WOMAN : Gender.MAN;
  }

}
6
KARASZI István

これは、実際には数回前に提案されたものです。したがって、RFEを提出することは理にかなっているかもしれません。これが機能する方法は複数あります。タイプに注釈を付ける機能(@ JsonPostProcess(Processor.class))と、モジュールAPIを介してポストプロセッサを登録する機能(Jacksonがデシリアライザーを構築するときに基本的にコールバックが発生するようにする機能)です。モジュールは、使用するポストプロセッサを指定します)。しかし、おそらくこれを行うためのさらに良い方法があります。

4
StaxMan

これはそのままではサポートされていませんが、逆シリアル化後に呼び出されるメソッドの@JsonPostDeserializeアノテーションを簡単に作成できます。

まず、注釈を定義します。

/**
 * Annotation for methods to be called directly after deserialization of the object.
 */
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface JsonPostDeserialize {
}

次に、次の登録コードと実装コードをプロジェクトに追加します。

public static void addPostDeserializeSupport(ObjectMapper objectMapper) {
    SimpleModule module = new SimpleModule();
    module.setDeserializerModifier(new BeanDeserializerModifier() {
        @Override
        public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDescription,
                JsonDeserializer<?> originalDeserializer) {
            return new CustomAnnotationsDeserializer(originalDeserializer, beanDescription);
        }
    });
    objectMapper.registerModule(module);
}

/**
 * Class implementing the functionality of the {@link JsonPostDeserialize} annotation.
 */
public class CustomAnnotationsDeserializer extends DelegatingDeserializer {
    private final BeanDescription beanDescription;

    public CustomAnnotationsDeserializer(JsonDeserializer<?> delegate, BeanDescription beanDescription) {
        super(delegate);
        this.beanDescription = beanDescription;
    }

    @Override
    protected JsonDeserializer<?> newDelegatingInstance(JsonDeserializer<?> newDelegatee) {
        return new CustomAnnotationsDeserializer(newDelegatee, beanDescription);
    }

    @Override
    public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        Object deserializedObject = super.deserialize(p, ctxt);

        callPostDeserializeMethods(deserializedObject);
        return deserializedObject;
    }

    private void callPostDeserializeMethods(Object deserializedObject) {
        for (AnnotatedMethod method : beanDescription.getClassInfo().memberMethods()) {
            if (method.hasAnnotation(JsonPostDeserialize.class)) {
                try {
                    method.callOn(deserializedObject);
                } catch (Exception e) {
                    throw new RuntimeException("Failed to call @JsonPostDeserialize annotated method in class "
                            + beanDescription.getClassInfo().getName(), e);
                }
            }
        }
    }
}

最後に、ObjectMapperインスタンスをaddPostDeserializeSupportで変更すると、逆シリアル化されたオブジェクトのすべての@JsonPostDeserializeアノテーション付きメソッドが呼び出されます。

0
oberlies