java - मैं जैक्सन में कस्टम deserializer से डिफ़ॉल्ट deserializer कैसे कॉल करूं?




spring hibernate (5)

जैक्सन में मुझे अपने कस्टम deserializer में एक समस्या है। मैं उस ऑब्जेक्ट को पॉप्युलेट करने के लिए डिफ़ॉल्ट सीरियलाइज़र तक पहुंच बनाना चाहता हूं जिसमें मैं deserializing हूँ। आबादी के बाद मैं कुछ कस्टम चीजें करूंगा लेकिन पहले मैं ऑब्जेक्ट को डिफॉल्ट जैक्सन व्यवहार से deserialize करना चाहता हूं।

यह वह कोड है जो इस समय मेरे पास है।

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

}

मुझे जो चाहिए वह डिफ़ॉल्ट deserializer को शुरू करने का एक तरीका है ताकि मैं अपना विशेष तर्क शुरू करने से पहले अपने POJO को पूर्व-पॉप्युलेट कर सकूं।

कस्टम deserializer के भीतर से deserialize बुलाते हुए यह seams वर्तमान संदर्भ से कहा जाता है इससे कोई फर्क नहीं पड़ता कि मैं serializer वर्ग कैसे बनाते हैं। मेरे POJO में एनोटेशन की वजह से। यह स्पष्ट कारणों से एक स्टैक ओवरफ़्लो अपवाद का कारण बनता है। मैंने एक बींडेसियलाइज़र शुरू करने की कोशिश की है लेकिन प्रक्रिया बेहद जटिल है और मैंने इसे करने का सही तरीका नहीं ढूंढ पाया है। मैंने एनोटेशन इंट्रोस्पेक्टर को ओवरलोड करने का भी प्रयास नहीं किया है, यह सोचने के लिए कि यह मुझे DeserializerContext में एनोटेशन को अनदेखा करने में मदद कर सकता है। आखिरकार यह लगता है कि मुझे जेसनडेसरियललाइज़र बिल्डर्स का उपयोग करके कुछ सफलता मिली हो सकती है, हालांकि मुझे वसंत से आवेदन संदर्भ को पकड़ने के लिए कुछ जादू सामग्री करने की आवश्यकता थी। मैं किसी भी चीज की सराहना करता हूं जो मुझे क्लीनर समाधान के लिए ले जा सकता है उदाहरण के लिए मैं जेसनडेसरियललाइज़र एनोटेशन पढ़ने के बिना एक Deserialization संदर्भ कैसे बना सकता हूं।


ऐसा करने के कुछ तरीके हैं, लेकिन इसे करने के लिए थोड़ा और काम शामिल है। असल में आप उप-वर्गीकरण का उपयोग नहीं कर सकते हैं, क्योंकि सूचना डिफ़ॉल्ट deserializers की आवश्यकता वर्ग परिभाषाओं से बनाया गया है।

तो आप BeanDeserializerModifier का निर्माण करने के लिए सबसे अधिक संभावना का उपयोग कर सकते हैं, Module इंटरफ़ेस के माध्यम से पंजीकृत करें ( SimpleModule उपयोग करें)। आपको modifyDeserializer को परिभाषित / ओवरराइड करने की आवश्यकता है, और विशिष्ट मामले के लिए जहां आप अपना तर्क जोड़ना चाहते हैं (जहां टाइप मैचों), अपना खुद का deserializer बनाएं, आपको दिया गया डिफ़ॉल्ट deserializer पास करें। और फिर deserialize() विधि में आप केवल कॉल प्रतिनिधि दे सकते हैं, परिणाम ऑब्जेक्ट ले लो।

वैकल्पिक रूप से, यदि आपको वास्तव में ऑब्जेक्ट बनाना और पॉप्युलेट करना है, तो आप ऐसा कर सकते हैं और deserialize() अधिभारित संस्करण को कॉल कर सकते हैं जो तीसरे तर्क को लेता है; deserialize करने के लिए वस्तु।

एक और तरीका जो काम कर सकता है (लेकिन 100% निश्चित नहीं) Converter ऑब्जेक्ट ( @JsonDeserialize(converter=MyConverter.class) निर्दिष्ट करना होगा)। यह एक नया जैक्सन 2.2 फीचर है। आपके मामले में, कन्वर्टर वास्तव में प्रकार को परिवर्तित नहीं करेगा, लेकिन ऑब्जेक्ट को संशोधित करने में आसान बनाता है: लेकिन मुझे नहीं पता कि यह आपको वही करने देगा जो आप चाहते हैं, क्योंकि डिफ़ॉल्ट deserializer पहले कहा जाएगा, और केवल तब ही आपका Converter


जैसा कि स्टैक्समैन ने पहले ही सुझाव दिया है कि आप इसे BeanDeserializerModifier और BeanDeserializerModifier माध्यम से पंजीकृत करके ऐसा कर सकते हैं। निम्नलिखित उदाहरण काम करना चाहिए:

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

मैं BeanSerializerModifier का उपयोग करने के साथ ठीक नहीं था क्योंकि यह कस्टम deserializer के बजाय केंद्रीय BeanSerializerModifier कुछ व्यवहारिक परिवर्तन घोषित करने के लिए मजबूर करता है और वास्तव में यह JsonSerialize साथ इकाई वर्ग को एनोटेट करने के समानांतर समाधान है। यदि आप इसे इसी तरह महसूस करते हैं, तो आप यहां मेरे उत्तर की सराहना कर सकते हैं: https://.com/a/43213463/653539


यदि आपके लिए अतिरिक्त उपयोगकर्ता वर्ग घोषित करना संभव है तो आप इसे एनोटेशन का उपयोग करके कार्यान्वित कर सकते हैं

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

}

टॉमस ज़लुस्की ने जो सुझाव दिया है , उसके साथ-साथ, बीनडिसेरियलाइज़र मोडिफायर का उपयोग करने वाले मामलों में अवांछनीय है, आप BeanDeserializerFactory का उपयोग करके खुद को एक डिफ़ॉल्ट deserializer BeanDeserializerFactory , हालांकि कुछ अतिरिक्त सेटअप आवश्यक है। संदर्भ में, यह समाधान इस तरह दिखेगा:

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




jackson