2015-01-09 4 views
20

साथ मैं एक वर्ग है जो निम्नको क्रमानुसार/deserialize नक्शा <स्ट्रिंग, वस्तु> जैक्सन

public class MyClass { 
    private String val1; 
    private String val2; 
    private Map<String,Object> context; 
    // Appropriate accessors removed for brevity. 
    ... 
} 

मैं JSON और वापस करने के लिए वस्तु से जैक्सन के साथ राउंड ट्रिप बनाने के लिए सक्षम होने के लिए देख रहा हूँ की तरह लग रहा है । मैं ठीक ऊपर वस्तु को क्रमानुसार और निम्नलिखित उत्पादन प्राप्त कर सकते हैं:

{ 
    "val1": "foo", 
    "val2": "bar", 
    "context": { 
     "key1": "enumValue1", 
     "key2": "stringValue1", 
     "key3": 3.0 
    } 
} 

मुद्दा मैं में चल रहा हूँ कि जब धारावाहिक मानचित्र में मानों किसी भी प्रकार की जानकारी नहीं है, वे सही ढंग से deserialized नहीं कर रहे हैं। उदाहरण के लिए, उपरोक्त नमूने में, enumValue1 को enum value के रूप में deserialized किया जाना चाहिए, लेकिन इसके बजाय एक स्ट्रिंग के रूप में deserialized है। मैंने विभिन्न प्रकार की चीज़ों के आधार पर उदाहरण देखने के लिए उदाहरण देखे हैं, लेकिन मेरे परिदृश्य में, मुझे नहीं पता कि किस प्रकार हैं (वे उपयोगकर्ता उत्पन्न वस्तुएं होंगी जिन्हें मैं पहले से नहीं जानता) इसलिए मुझे होना चाहिए कुंजी मूल्य जोड़ी के साथ प्रकार की जानकारी क्रमबद्ध करने में सक्षम। मैं जैक्सन के साथ इसे कैसे पूरा कर सकता हूं?

रिकॉर्ड के लिए, मैं जैक्सन संस्करण 2.4.2 का उपयोग कर रहा हूं।

@Test 
@SuppressWarnings("unchecked") 
public void testJsonSerialization() throws Exception { 
    // Get test object to serialize 
    T serializationValue = getSerializationValue(); 
    // Serialize test object 
    String json = mapper.writeValueAsString(serializationValue); 
    // Test that object was serialized as expected 
    assertJson(json); 
    // Deserialize to complete round trip 
    T roundTrip = (T) mapper.readValue(json, serializationValue.getClass()); 
    // Validate that the deserialized object matches the original one 
    assertObject(roundTrip); 
} 

इस के बाद से एक स्प्रिंग आधारित परियोजना है, नक्शाकार इस प्रकार बनाया जा रहा है:

@Configuration 
public static class SerializationConfiguration { 

    @Bean 
    public ObjectMapper mapper() { 
     Map<Class<?>, Class<?>> mixins = new HashMap<Class<?>, Class<?>>(); 
     // Add unrelated MixIns 
     .. 

     return new Jackson2ObjectMapperBuilder() 
       .featuresToDisable(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS) 
       .dateFormat(new ISO8601DateFormatWithMilliSeconds()) 
       .mixIns(mixins) 
       .build(); 
    } 
} 
+4

ठीक है, निश्चित रूप से कि 'ऑब्जेक्ट' में कोई प्रकार की जानकारी नहीं होगी; इसके अलावा 1 के अलावा कोई रास्ता नहीं है। अपने 'संदर्भ' आवृत्ति चर (पसंदीदा) के लिए POJO बनाएं; या 2. 'मानचित्र <स्ट्रिंग, ऑब्जेक्ट>' लेकिन 'ऑब्जेक्ट नोड' का उपयोग न करें। किसी भी घटना में, यह कोड गंध का एक प्राथमिक उदाहरण है। – fge

+0

'संदर्भ' चर का उपयोग 'एचटीपीएसशन' के समान फैशन में किया जा रहा है (यह वसंत बैच के 'निष्पादन कॉन्टेक्स्ट' को सटीक होने का प्रतिनिधित्व करता है) इसलिए मैं इसे गंध नहीं मानूंगा ... यह एक 'मानचित्र' है। जो मुझे समझ में नहीं आता है वह क्यों जैक्सन उस क्षेत्र को जोड़ नहीं सकता है जो इस प्रकार को इंगित करता है। यदि इसका मूल्य है, तो इसमें कक्षा है, और इसलिए प्रकार निर्धारित कर सकते हैं। मैं क्या खो रहा हूँ? –

+0

और यह क्षेत्र कहां जोड़ देगा? आप केवल इसे 'ऑब्जेक्ट' के लिए deserialize करने के लिए कहते हैं। कम से कम 'ऑब्जेक्ट नोड' के साथ लाभ यह है कि आप सीधे जेएसओएन प्राप्त करते हैं; इसलिए आप फ़ील्ड के प्रकार से पूछ सकते हैं कि 'जेसन नोड' की मदद करनी है। – fge

उत्तर

15

मैं सबसे आसान तरीका लगता है कोड मैं राउंड ट्रिप का परीक्षण करने का उपयोग कर रहा इस प्रकार है जो आप चाहते हैं उसे हासिल करने के लिए:

ObjectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); 

यह धारावाहिक जेसन में प्रकार की जानकारी जोड़ देगा।

यहाँ आप एक चल उदाहरण हैं, कि तुम वसंत के लिए अनुकूल करने की आवश्यकता होगी:

public class Main { 

    public enum MyEnum { 
     enumValue1 
    } 

    public static void main(String[] args) throws IOException { 
     ObjectMapper mapper = new ObjectMapper(); 

     MyClass obj = new MyClass(); 
     obj.setContext(new HashMap<String, Object>()); 

     obj.setVal1("foo"); 
     obj.setVal2("var"); 
     obj.getContext().put("key1", "stringValue1"); 
     obj.getContext().put("key2", MyEnum.enumValue1); 
     obj.getContext().put("key3", 3.0); 

     mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); 
     String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj); 

     System.out.println(json); 

     MyClass readValue = mapper.readValue(json, MyClass.class); 
     //Check the enum value was correctly deserialized 
     Assert.assertEquals(readValue.getContext().get("key2"), MyEnum.enumValue1); 
    } 

} 

वस्तु के लिए कुछ इसी तरह में धारावाहिक रूप दिया जाएगा:

[ "so_27871226.MyClass", { 
    "val1" : "foo", 
    "val2" : "var", 
    "context" : [ "java.util.HashMap", { 
    "key3" : 3.0, 
    "key2" : [ "so_27871226.Main$MyEnum", "enumValue1" ], 
    "key1" : "stringValue1" 
    } ] 
} ] 

और वापस सही ढंग से deserialized हो जाएगा , और दावा पारित होगा।

Bytheway ऐसा करने के और तरीके हैं, कृपया अधिक जानकारी के लिए https://github.com/FasterXML/jackson-docs/wiki/JacksonPolymorphicDeserialization देखें।

मुझे आशा है कि इससे मदद मिलेगी।

+0

वही है जो मैं ढूंढ रहा हूं। एक छोटा सवाल यह एक वैश्विक स्तर पर है। क्या इसे फ़ील्ड स्तर पर निर्दिष्ट करने का कोई तरीका है (केवल एक फ़ील्ड है जिसके साथ मुझे यह समस्या है, इसलिए JSON को हर जगह प्रकार के साथ कूड़े नहीं करना अच्छा होगा)। कोई बड़ा सौदा नहीं है, लेकिन पूछने के लिए चोट नहीं पहुंचा सकता है। –

+1

धन्यवाद श्रीमान, आपने मेरे दर्द के घंटे समाप्त कर दिए हैं – James

+1

मेरा मानना ​​है कि इस विकल्प को सक्षम करने से आपके ऑब्जेक्ट क्रमबद्धता द्वारा उत्पादित JSON अप्रत्याशित रूप से प्रभावित हो सकता है। तो मैं इस मामले के लिए एक वैश्विक विकल्प सक्षम करने का समर्थन नहीं करता। मुझे उम्मीद है कि जब मैं एक मानचित्र/संग्रह में एक पॉलिमॉर्फिक उदाहरण जोड़ता हूं तो प्रकार क्रमबद्धता विकल्पों को अनदेखा नहीं किया जाता है। आश्चर्य की बात है कि, जब पॉलिमॉर्फिक ऑब्जेक्ट कंटेनर/एग्रीगेशन ऑब्जेक्ट के अंतर्गत मौजूद होता है, तो क्रमबद्धता विकल्प अपेक्षा के अनुसार लागू होते हैं। –

संबंधित मुद्दे