java バージョン Jacksonのカスタムデシリアライザからデフォルトのデシリアライザを呼び出す方法




java api 呼び出し json (6)

StaxManは、 BeanDeserializerModifierを作成し、それをSimpleModule経由で登録することでこれを行うことができます。 次の例で動作するはずです。

public class UserEventDeserializer extends StdDeserializer<User> implements ResolvableDeserializer
{
  private static final long serialVersionUID = 7923585097068641765L;

  private final JsonDeserializer<?> defaultDeserializer;

  public UserEventDeserializer(JsonDeserializer<?> defaultDeserializer)
  {
    super(User.class);
    this.defaultDeserializer = defaultDeserializer;
  }

  @Override public User deserialize(JsonParser jp, DeserializationContext ctxt)
      throws IOException, JsonProcessingException
  {
    User deserializedUser = (User) defaultDeserializer.deserialize(jp, ctxt);

    // Special logic

    return deserializedUser;
  }

  // for some reason you have to implement ResolvableDeserializer when modifying BeanDeserializer
  // otherwise deserializing throws JsonMappingException??
  @Override public void resolve(DeserializationContext ctxt) throws JsonMappingException
  {
    ((ResolvableDeserializer) defaultDeserializer).resolve(ctxt);
  }


  public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException
  {
    SimpleModule module = new SimpleModule();
    module.setDeserializerModifier(new BeanDeserializerModifier()
    {
      @Override public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer)
      {
        if (beanDesc.getBeanClass() == User.class)
          return new UserEventDeserializer(deserializer);
        return deserializer;
      }
    });


    ObjectMapper mapper = new ObjectMapper();
    mapper.registerModule(module);
    User user = mapper.readValue(new File("test.json"), User.class);
  }
}

ジャクソンのカスタムデシリアライザに問題があります。 私はデシリアライズしようとしているオブジェクトを移入するためにデフォルトのシリアライザにアクセスしたいと思います。 母集団の後に私はいくつかのカスタムなことを行いますが、最初にデフォルトのjacksonの振る舞いでオブジェクトを逆直列化したいと思います。

これは私が現在持っているコードです。

public class UserEventDeserializer extends StdDeserializer<User> {

  private static final long serialVersionUID = 7923585097068641765L;

  public UserEventDeserializer() {
    super(User.class);
  }

  @Override
  @Transactional
  public User deserialize(JsonParser jp, DeserializationContext ctxt)
      throws IOException, JsonProcessingException {

    ObjectCodec oc = jp.getCodec();
    JsonNode node = oc.readTree(jp);
    User deserializedUser = null;
    deserializedUser = super.deserialize(jp, ctxt, new User()); 
    // The previous line generates an exception java.lang.UnsupportedOperationException
    // Because there is no implementation of the deserializer.
    // I want a way to access the default spring deserializer for my User class.
    // How can I do that?

    //Special logic

    return deserializedUser;
  }

}

私が必要とするのは、デフォルトのデシリアライザを初期化して、私の特別なロジックを開始する前にPOJOをあらかじめ設定できるようにする方法です。

カスタムデシリアライザ内からdeserializeを呼び出すときは、シリアライザクラスをどのように構築しても、現在のコンテキストからメソッドが呼び出されます。 私のPOJOの注釈のため。 これは明らかな理由によりスタックオーバーフロー例外を引き起こします。 私はbeandeserializerを初期化しようとしましたが、プロセスは非常に複雑で、私はそれを行う正しい方法を見つけることができませんでした。 私は、DeserializerContextの注釈を無視するのに役立つかもしれないと考えて、注釈イントロスペクターを無駄にオーバーロードしようとしました。 最後に、私はJsonDeserializerBuildersを使っていくつかの成功を収めたかもしれませんが、これは私が春からアプリケーションコンテキストを取得するためにいくつかの魔法のことをする必要がありました。 私は、JsonDeserializerアノテーションを読まずに逆直列化コンテキストを構築できますか?


Answer #1

私はBeanSerializerModifierを使用してもOKではありませんでした。カスタムのデシリアライザ自体ではなく、中央のObjectMapperでいくつかの動作の変更を宣言する必要があり、実際にJsonSerializeエンティティクラスに注釈を付ける並列ソリューションJsonSerialize 。 あなたがそれを同じように感じるなら、私の答えはここにありますhttps://.com/a/43213463/653539 : https://.com/a/43213463/653539


Answer #2

DeserializationContextは、使用できるreadValue()メソッドがあります。 これはデフォルトのデシリアライザと独自のカスタムデシリアライザの両方で動作するはずです。

readValue()を渡すJsonParserを取得するために、読みたいJsonNodeレベルでtraverse()を呼び出してください。

public class FooDeserializer extends StdDeserializer<FooBean> {

    private static final long serialVersionUID = 1L;

    public FooDeserializer() {
        this(null);
    }

    public FooDeserializer(Class<FooBean> t) {
        super(t);
    }

    @Override
    public FooBean deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        JsonNode node = jp.getCodec().readTree(jp);
        FooBean foo = new FooBean();
        foo.setBar(ctxt.readValue(node.get("bar").traverse(), BarBean.class));
        return foo;
    }

}

Answer #3

TomášZáluskýが提案している行に沿って、 BeanDeserializerModifierを使用することが望ましくない場合、 BeanDeserializerModifierを使用して、デフォルトのデシリアライザを自分で作成することができますが、特別な設定が必要です。 コンテキストでは、このソリューションは次のようになります。

public User deserialize(JsonParser jp, DeserializationContext ctxt)
  throws IOException, JsonProcessingException {

    ObjectCodec oc = jp.getCodec();
    JsonNode node = oc.readTree(jp);
    User deserializedUser = null;

    DeserializationConfig config = ctxt.getConfig();
    JsonDeserializer<Object> defaultDeserializer = BeanDeserializerFactory.instance.buildBeanDeserializer(ctxt, User.class, config.introspect(User.class));

    if (defaultDeserializer instanceof ResolvableDeserializer) {
        ((ResolvableDeserializer) defaultDeserializer).resolve(ctxt);
    }

    JsonParser treeParser = oc.treeAsTokens(node);
    config.initialize(treeParser);

    if (treeParser.getCurrentToken() == null) {
        treeParser.nextToken();
    }

    deserializedUser = (User) defaultDeserializer.deserialize(treeParser, context);

    return deserializedUser;
}

Answer #4

これを行うにはいくつかの方法がありますが、それを正しく行うにはもう少し作業が必要です。 基本的には、情報のデフォルトデシリアライザの必要性はクラス定義から構築されるため、サブクラスを使用することはできません。

だからあなたが最もよく使うことのできるのは、 BeanDeserializerModifierを構築し、それをModuleインタフェース経由で登録することです( SimpleModule使用しSimpleModule )。 あなたはmodifyDeserializerを定義/オーバーライドする必要があります。独自のロジック(型が一致する場所)を追加したい場合、独自のデシリアライザを作成し、与えられたデフォルトのデシリアライザを渡します。 そして、 deserialize()メソッドでは、呼び出しを委譲してresultオブジェクトを取り出すことができます。

また、オブジェクトを実際に作成して移入する必要がある場合は、そうすることができ、第3引数をとるオーバーロードされたバージョンのdeserialize()を呼び出すことができます。 デシリアライズするオブジェクト。

(100%確実ではない)もう一つの方法はConverterオブジェクト( @JsonDeserialize(converter=MyConverter.class) )を指定することです。 これはJackson 2.2の新しい機能です。 あなたのケースでは、Converterは実際にはタイプを変換しませんが、オブジェクトの変更を簡略化します。しかし、デフォルトのデシリアライザが最初に呼び出され、 Converterだけが必要なので、


Answer #5

余分なUserクラスを宣言することが可能な場合は、アノテーションを使用するだけで実装できます

// your class
@JsonDeserialize(using = UserEventDeserializer.class)
public class User {
...
}

// extra user class
// reset deserializer attribute to default
@JsonDeserialize
public class UserPOJO extends User {
}

public class UserEventDeserializer extends StdDeserializer<User> {

  ...
  @Override
  public User deserialize(JsonParser jp, DeserializationContext ctxt)
      throws IOException, JsonProcessingException {
    // specify UserPOJO.class to invoke default deserializer
    User deserializedUser = jp.ReadValueAs(UserPOJO.class);
    return deserializedUser;

    // or if you need to walk the JSON tree

    ObjectMapper mapper = (ObjectMapper) jp.getCodec();
    JsonNode node = oc.readTree(jp);
    // specify UserPOJO.class to invoke default deserializer
    User deserializedUser = mapper.treeToValue(node, UserPOJO.class);

    return deserializedUser;
  }

}




jackson