property - json to class java jackson




我如何從傑克遜的一個自定義解串器中調用默認的解串器 (5)

我在傑克遜的自定義解串器中遇到問題。 我想訪問默認的序列化程序來填充我要反序列化的對象。 人口後我會做一些自定義的事情,但首先我想用默認的傑克遜行為反序列化對象。

這是我目前的代碼。

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,但這個過程非常複雜,我還沒有設法找到正確的方法來做到這一點。 我也嘗試重載註釋introspector無濟於事,認為它可能會幫助我忽略DeserializerContext中的註釋。 最後它接縫我可能已經使用JsonDeserializerBuilders取得了一些成功,儘管這需要我做一些魔術來從spring中獲取應用程序上下文。 我會很感激任何可能導致我更清晰的解決方案的事情,例如,如何在不讀取JsonDeserializer註釋的情況下構建反序列化上下文。


DeserializationContext有一個你可以使用的readValue()方法。 這應該適用於默認的反序列化器和您擁有的任何自定義反序列化器。

只要確保在要讀取的JsonNode級別上調用traverse()來檢索JsonParser以傳遞給readValue()

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

}

如果您可以聲明額外的用戶類,那麼您可以使用註釋來實現它

// 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;
  }

}

我不喜歡使用BeanSerializerModifier因為它強制在中心ObjectMapper聲明一些行為更改,而不是在自定義反序列化器本身中,實際上它是使用JsonSerialize註釋實體類的並行解決方案。 如果你覺得它類似的方式,你可能會喜歡我的答案在這裡: https://.com/a/43213463/653539 : https://.com/a/43213463/653539


有幾種方法可以做到這一點,但要做到這一點需要更多的工作。 基本上你不能使用子分類,因為信息默認的反序列化器需要從類定義中構建。

所以你最可能使用的是構造一個BeanDeserializerModifier ,通過Module接口註冊(使用SimpleModule )。 您需要定義/重寫modifyDeserializer ,並且對於您想添加自己的邏輯(其中類型匹配)的特定情況,構建您自己的解串器,傳遞給定的默認解串器。 然後在deserialize()方法中,您可以委託調用,接受結果Object。

或者,如果您必須實際創建並填充對象,則可以這樣做,並調用deserialize()第三個參數的deserialize()重載版本; 反序列化的對象。

可能工作的另一種方式(但不是100%肯定)將指定Converter對象( @JsonDeserialize(converter=MyConverter.class) )。 這是一個新的傑克遜2.2功能。 在你的情況下,轉換器實際上不會轉換類型,但可以簡化修改對象:但是我不知道這是否會讓你按照自己的意思去做,因為默認的反序列化器會先被調用,然後才是你的Converter


由於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