2015-12-10 8 views
8

जैक्सन वास्तव में कुछ विचित्र कर रहा है और मुझे इसके लिए कोई स्पष्टीकरण नहीं मिल रहा है। मैं polymorphic serialization कर रहा हूँ और यह पूरी तरह से काम करता है जब एक वस्तु अपने आप पर है। लेकिन यदि आप एक ही वस्तु को एक सूची में डालते हैं और इसके बजाय सूची को क्रमबद्ध करते हैं, तो यह प्रकार की जानकारी मिटा देता है।जैक्सन पॉलिमॉर्फिक धारावाहिक सूचियों में क्यों काम नहीं करता है?

तथ्य यह है कि यह टाइपिंग जानकारी खो रहा है, जिससे किसी को टाइप एरर पर संदेह होगा। लेकिन यह सूची के सामग्री के क्रमिकरण के दौरान हो रहा है; सभी जैक्सन को करना है कि वर्तमान वस्तु का निरीक्षण करें, यह इसके प्रकार को निर्धारित करने के लिए क्रमबद्ध है।

मैं एक उदाहरण जैक्सन 2.5.1 का उपयोग कर बना लिया है:

import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 
import com.fasterxml.jackson.annotation.JsonSubTypes; 
import com.fasterxml.jackson.annotation.JsonSubTypes.Type; 
import com.fasterxml.jackson.annotation.JsonTypeInfo; 
import com.fasterxml.jackson.annotation.JsonTypeName; 
import com.fasterxml.jackson.core.JsonProcessingException; 
import com.fasterxml.jackson.databind.ObjectMapper; 

import java.util.ArrayList; 
import java.util.List; 

public class Test { 

    @JsonIgnoreProperties(ignoreUnknown = true) 
    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY) 
    @JsonSubTypes({ 
    @Type(value = Dog.class, name = "dog"), 
    @Type(value = Cat.class, name = "cat")}) 
    public interface Animal {} 

    @JsonTypeName("dog") 
    public static class Dog implements Animal { 
    private String name; 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 
    } 

    @JsonTypeName("cat") 
    public static class Cat implements Animal { 
    private String name; 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 
    } 

    public static void main(String[] args) throws JsonProcessingException { 
    List<Cat> list = new ArrayList<>(); 
    list.add(new Cat()); 
    System.out.println(new ObjectMapper().writeValueAsString(list)); 
    System.out.println(new ObjectMapper().writeValueAsString(list.get(0))); 
    } 
} 

यहाँ उत्पादन है:

[{"name":null}] 
{"@type":"cat","name":null} 

आप देख सकते हैं, जैक्सन प्रकार की जानकारी को जोड़ने नहीं है जब वस्तु है एक सूची में क्या किसी को पता है कि ये क्यों हो रहा है?

उत्तर

13

ऐसा क्यों होता है इसके विभिन्न कारणों पर चर्चा की जाती है here और here। मैं जरूरी कारणों से सहमत नहीं हूं, लेकिन टाइप एरर के कारण जैक्सन बल्ले से List (या Collection या Map) तत्वों के प्रकार को जानता है। यह एक साधारण धारावाहिक का उपयोग करने का विकल्प चुनता है जो आपकी टिप्पणियों की व्याख्या नहीं करता है।

सबसे पहले, आप एक वर्ग है कि List<Cat> लागू करता है बनाने के लिए यह उचित रूप से दृष्टांत और उदाहरण को क्रमानुसार कर सकते हैं:

आपके पास दो विकल्प उन लिंक्स में सुझाव दिया है।

class CatList implements List<Cat> {...} 

सामान्य प्रकार तर्क Cat गुम नहीं होता। जैक्सन के पास इसका उपयोग है और इसका उपयोग करता है।

दूसरा, आप List<Cat> प्रकार के लिए ObjectWriter को तत्काल और उपयोग कर सकते हैं। उदाहरण

लिए
System.out.println(new ObjectMapper().writerFor(new TypeReference<List<Cat>>() {}).writeValueAsString(list)); 

प्रिंट होगा

[{"@type":"cat","name":"heyo"}] 
+0

इसके अलावा, आप 'नई ObjectMapper() की तरह उपयोग कर सकते हैं writerFor (mapper.getTypeFactory() constructCollectionType (List.class, पशु।। कक्षा))। लिखें वैल्यूएस्ट्रिंग (सूची) ' –

+0

यह वास्तव में अजीब है, और मैं कल्पना नहीं कर सकता कि वे यह विकल्प क्यों बनायेंगे। सूची के प्रकार के बावजूद, आपको लगता है कि इसके अंदर की वस्तुओं को हर समय समान रूप से क्रमबद्ध किया जाएगा। – monitorjbl

+0

mapper.writerWithType (mapper.getTypeFactory()। BuildCollectionType (List.class, Animal.class))। लिखें ValueAsString (सूची) – Youness

11

जवाब सोटीरिओस Delimanolis दिया सही से एक है। हालांकि, मैंने सोचा कि इस कामकाज को एक अलग उत्तर के रूप में पोस्ट करना अच्छा लगेगा। यदि आप ऐसे माहौल में हैं जिसमें आप ऑब्जेक्टमैपर को प्रत्येक प्रकार की चीज़ के लिए नहीं बदल सकते हैं जिसे आपको वापस करने की आवश्यकता है (जैसे जर्सी/स्प्रिंगएमवीसी वेबएप), तो एक विकल्प है।

आप उस श्रेणी में एक निजी अंतिम क्षेत्र शामिल कर सकते हैं जिसमें प्रकार शामिल है। यह क्षेत्र कक्षा के बाहर किसी भी चीज के लिए दृश्यमान नहीं होगा, लेकिन यदि आप इसे @JsonProperty("@type") (या "@class" या जो कुछ भी आपके प्रकार के फ़ील्ड का नाम दिया गया है) के साथ एनोटेट करें, जैक्सन ऑब्जेक्ट कहां स्थित है, इस पर ध्यान दिए बिना जैक्सन इसे क्रमबद्ध करेगा।

@JsonTypeName("dog") 
public static class Dog implements Animal { 
    @JsonProperty("@type") 
    private final String type = "dog"; 
    private String name; 

    public String getName() { 
    return name; 
    } 

    public void setName(String name) { 
    this.name = name; 
    } 
} 
+0

मैं कक्षाओं (स्प्रिंग प्रोजेक्शन) के बजाय इंटरफेस का उपयोग करता हूं। यह मेरे लिए काम नहीं किया। कोई सुझाव कृपया? –

+0

यह मेरे लिए काम करता है, लेकिन जब मैंने एक तत्व को क्रमबद्ध किया, तो @type फ़ील्ड डुप्लीकेट किया गया है। –

0

सरणियों प्रकार विलोपन का उपयोग नहीं करते जैसा कि आप इसे एक सरणी में संग्रह को बदलने के लिए ObjectMapper.writeValueAsString अधिभावी हल कर सकते हैं।

public class CustomObjectMapper extends ObjectMapper {  
    @Override 
     public String writeValueAsString(Object value) throws JsonProcessingException { 
       //Transform Collection to Array to include type info 
       if(value instanceof Collection){ 
        return super.writeValueAsString(((Collection)value).toArray()); 
       } 
       else 
        return super.writeValueAsString(value); 
      } 
} 

इसे अपने परीक्षण में उपयोग करें।मुख्य:

System.out.println(new CustomObjectMapper().writeValueAsString(list)); 

आउटपुट (बिल्लियों और कुत्तों सूची):।

[{"@type":"cat","name":"Gardfield"},{"@type":"dog","name":"Snoopy"}] 
संबंधित मुद्दे