2015-04-28 12 views
6

का उपयोग करते हुए JSON को deserializing जब डिफ़ॉल्ट डिफ़ॉल्ट मान लागू करते हैं जब विभिन्न JSON संदेशों को deserializing, मैं एक निश्चित प्रकार के विशेषताओं के लिए एक डिफ़ॉल्ट मान प्रदान करना चाहता हूं। कक्षा में मूल्य निर्दिष्ट करने के लिए यह generally suggested है, लेकिन यदि आपको कई कक्षाओं में ऐसा करना है तो यह त्रुटि-प्रवण है। आप एक को भूल सकते हैं और डिफ़ॉल्ट मान के बजाय null के साथ समाप्त हो सकते हैं। मेरा इरादा प्रत्येक संपत्ति को Optional<T> से Optional.absent पर सेट करना है। चूंकि null ठीक है Optional जैक्सन के साथ उनका उपयोग करके निराशाजनक साबित हुआ है, इसे खत्म करने की कोशिश कर रहा है।जैक्सन

जैक्सन की अधिकांश विशेषताएं जो आपको जेएसओएन पर deserialization प्रक्रिया फोकस को अनुकूलित करने की अनुमति देती हैं, जो कि ऑब्जेक्ट को तत्काल करने की प्रक्रिया के आसपास नहीं है, जो आप चाहते हैं। निकटतम मैं एक सामान्य समाधान के लिए हो रही हो रहे हैं मेरे अपने ValueInstantiator निर्माण कर रहा है, लेकिन वहाँ दो शेष मुद्दों मैं कर रहे हैं:

  • मैं इसे कैसे केवल absent रूप Optional का दृष्टांत नहीं लेकिन के बाकी के साथ हस्तक्षेप कर सकता हूँ तत्काल प्रक्रिया?
  • मैं अपने परिणाम को ObjectMapper में अंतिम परिणाम कैसे तारूं?

अद्यतन: मैं स्पष्ट करने के लिए है कि मैं एक समाधान है कि संशोधित प्रत्येक क्लास कि Optional के शामिल शामिल नहीं रहा हूँ चाहता हूँ। मैं डीआरवाई सिद्धांत का उल्लंघन करने का विरोध कर रहा हूं। जब भी हम Optional को नई या मौजूदा कक्षा में जोड़ते हैं, तो मुझे या मेरे सहयोगियों को कुछ अतिरिक्त करने के बारे में सोचना नहीं चाहिए। मैं यह कहने में सक्षम होना चाहता हूं, "हर कक्षा में प्रत्येक वैकल्पिक क्षेत्र को मैं Absent से पहले भर चुका हूं," केवल एक बार, और इसके साथ किया जाना चाहिए।

निम्नलिखित इसका मतलब है कि बाहर कर रहे हैं:

  • सार माता पिता वर्ग (घोषित करने के लिए की जरूरत है)
  • कस्टम बिल्डर/निर्माता/JsonDeserializer (प्रत्येक लागू वर्ग पर टिप्पणी की जरूरत है)
  • Mixin के? मैंने प्रतिबिंब के साथ संयुक्त प्रयास किया, लेकिन मुझे नहीं पता कि कक्षा में मुझे कैसे पहुंचाया जा रहा है ...

उत्तर

1

आप डिफ़ॉल्ट मान को संभालने के लिए एक कस्टम deserializer लिख सकते हैं। प्रभावी रूप से आप उस वस्तु के प्रकार के लिए उपयुक्त deserializer का विस्तार करेंगे, जिसे आप deserializing कर रहे हैं, deserialized मूल्य प्राप्त करें, और यदि यह null है तो बस उचित डिफ़ॉल्ट मान वापस करें।

ObjectMapper objectMapper = new ObjectMapper(); 
objectMapper.registerModule(new DefaultStringModule()); 

क्षेत्रों के लिए डिफ़ॉल्ट मान नहीं संभाल करने के लिए:

public class DefaultStringModule extends SimpleModule { 
    private static final String NAME = "DefaultStringModule"; 

    private static final String DEFAULT_VALUE = "[DEFAULT]"; 

    public DefaultStringModule() { 
     super(NAME, ModuleVersion.instance.version()); 
     addDeserializer(String.class, new DefaultStringDeserializer()); 
    } 

    private static class DefaultStringDeserializer extends StdScalarDeserializer<String> { 
     public DefaultStringDeserializer() { 
      super(String.class); 
     } 

     public String deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException, JsonProcessingException { 
      String deserialized = jsonParser.getValueAsString(); 

      // Use a default value instead of null 
      return deserialized == null ? DEFAULT_VALUE : deserialized; 
     } 

     @Override 
     public Object deserializeWithType(JsonParser jp, DeserializationContext ctxt, TypeDeserializer typeDeserializer) throws IOException { 
      return deserialize(jp, ctxt); 
     } 
    } 
} 

एक ObjectMapper के साथ इस का उपयोग करने के लिए आप उदाहरण पर मॉड्यूल रजिस्टर कर सकते हैं:

यहाँ एक त्वरित तरीका स्ट्रिंग्स के साथ यह करने के लिए है जेएसओएन में मौजूद, मैंने आमतौर पर इसे बिल्डर क्लास के उपयोग के माध्यम से देखा है जो कि आपूर्ति किए गए मानों का उपयोग करके वर्ग का निर्माण करेगा और लापता फ़ील्ड के लिए कोई डिफ़ॉल्ट मान जोड़ देगा। फिर, deserialized वर्ग (उदा। MyClass) पर, @JsonDeserialize(builder = MyClass.Builder.class) एनोटेशन जोड़ें ताकि जैक्सन को MyClass को बिल्डर वर्ग के माध्यम से deserialize करने के लिए इंगित किया जा सके।

+0

इस समस्या के साथ समस्या है कि 'deserialize() 'को नहीं कहा जाता है यदि विशेषता जेएसओएन में नहीं है। मैं चाहता हूं कि उन्हें 'वैकल्पिक' एब्सेंट 'में मैप किया जाए। –

+0

क्षमा करें, उस भाग को याद किया। मैं अपने जवाब के अंत में एक पैराग्राफ जोड़ता हूं ताकि यह सुझाव दिया जा सके कि मैंने यह किया है। –

+0

बेहतर, लेकिन फिर भी मुझे प्रत्येक वर्ग को एनोटेट करना होगा जिसमें वैकल्पिक गुण हैं। मैं इसे पारदर्शी होना चाहता हूं। –

2

java.lang.Optional के लिए विशेष रूप से, जैक्सन लोग खुद से एक मॉड्यूल है: https://github.com/FasterXML/jackson-datatype-jdk8

अमरूद वैकल्पिक द्वारा https://github.com/FasterXML/jackson-datatype-guava

कवर किया जाता है यह अशक्त के लिए एक Optional.absent निर्माण करेंगे, लेकिन के लिए नहीं अनुपस्थित JSON मूल्यों :-(।

https://github.com/FasterXML/jackson-databind/issues/618 देखें और https://github.com/FasterXML/jackson-datatype-jdk8/issues/2

तो तुम कर रहे हैं अपने Optionals आरंभ के साथ फंस बस के रूप में आप सह प्रारंभ करना चाहिए llections। यह एक अच्छा अभ्यास है, इसलिए आप इसे लागू करने में सक्षम होना चाहिए।

private Optional<Xxx> xxx = Optional.absent(); 
private List<Yyy> yyys = Lists.newArrayList(); 
+0

नहीं, मैं बाद वाले का उपयोग कर रहा हूं और यह अनुपस्थित मानों को शून्य छोड़ देता है। मुझे नहीं लगता कि यह मूल रूप से मूल के लिए होगा, लेकिन मैं जांच सकता हूं। –

+0

यूप, एक ही समस्या। अनुपस्थित मानों पर कोई पासा नहीं :( –

+0

वास्तव में अमरूद 'वैकल्पिक' deserializer वास्तव में नवीनतम संस्करणों के साथ JSON 'null' को" अनुपस्थित "के रूप में deserialize करना चाहिए। कम से कम 2.5.3 का उपयोग करें। सीरियलाइजेशन एक और मामला है, हालांकि अनुपस्थित मान" शून्य -equivalent "तो डिफ़ॉल्ट समावेशन के आधार पर उन्हें छीन लिया जा सकता है। लेकिन JSON में किसी संपत्ति के लिए कोई मूल्य नहीं है (जैक्सन द्वारा कुछ भी नहीं किया गया है) और स्पष्ट JSON शून्य। – StaxMan

1

आपकी मूल्य वस्तु को इन मानों को अनुपस्थित के रूप में प्रारंभ करना चाहिए। यह सुनिश्चित करने का तरीका है कि डिफ़ॉल्ट मानों में कोई शून्य नहीं है। गुवा मॉड्यूल के Optional हैंडलर को वास्तव में उन्हें बाद में संस्करणों के साथ "अनुपस्थित" (स्पष्ट JSON नल के साथ), और कभी भी नल के रूप में deserialize करना चाहिए। लेकिन चूंकि जैक्सन केवल जेएसओएन गुणों पर काम करता है जो मौजूद हैं (और उन चीजों पर नहीं जो मौजूद हो सकते हैं लेकिन नहीं), पीओजेओ को अभी भी डिफ़ॉल्ट अनुपस्थित असाइनमेंट की आवश्यकता है।