2013-02-12 54 views
10

मान लीजिए मैं निम्नलिखित तीन वर्गों (getters और setters संक्षिप्तता के लिए बाहर छोड़ दिया) हैजैक्सन जेएसओएन जेनरेटर का उपयोग करके, मैं एक क्षेत्र में कई ऑब्जेक्ट्स कैसे लिख सकता हूं?

{ 
    "allInfo":{ 
     "fieldA":"foo", 
     "fieldB":"bar" 
    } 
} 
:

@JsonAutoDetect 
public class InfoCollection{ 
    private InfoType1 info1; 
    private InfoType2 info2; 
} 

@JsonAutoDetect 
public class InfoType1{ 
    private String fieldA; 
} 

@JsonAutoDetect 
public class InfoType2{ 
    private String fieldB; 
} 

मैं "मी एक JsonSerializer.serialize() समारोह है कि इस प्रारूप में एक InfoCollection वस्तु को धारावाहिक लिखने की कोशिश कर

यह वही है मैं अब है:

jsonGenerator.writeStartObject(); 
jsonGenerator.writeFieldName("allInfo"); 
jsonGenerator.writeObject(myInfoCollection.getInfo1()); 
jsonGenerator.writeObject(myInfoCollection.getInfo2()); 
jsonGenerator.writeEndObject(); 

जो निम्न अपवाद उत्पन्न कर रहा है:

org.codehaus.jackson.JsonGenerationException: Can not start an object, expecting field name 

क्या मुझे कुछ छोटा याद आ रहा है या क्या मैं पूरी तरह गलत तरीके से इस बारे में जा रहा हूं?

नोट: प्रस्तावित समाधान के एक जोड़े को अब तक InfoType1 और InfoType2 के प्रत्येक व्यक्ति के क्षेत्र लेखन शामिल है। मैं ऐसे समाधान की तलाश में हूं जिसके लिए इसकी आवश्यकता नहीं है क्योंकि मैं कई क्षेत्रों के साथ विशाल वर्गों पर समाधान का उपयोग करना चाहता हूं।

उत्तर

3

भविष्य में, जब आपके पास स्टैक ट्रेस होता है, तो हमें बताएं कि समस्या किस पंक्ति में दिखाई देती है।

जिसके अनुसार, ठीक शायद है:

jsonGenerator.writeStartObject(); 
jsonGenerator.writeFieldName("allInfo"); 

jsonGenerator.writeStartObject(); // start nested object 
jsonGenerator.writeFieldName("fieldA"); // start field 
jsonGenerator.writeObject(myInfoCollection.getInfo1().fieldA); 

jsonGenerator.writeFieldName("fieldB"); // start fieldB 
jsonGenerator.writeObject(myInfoCollection.getInfo2().fieldB); 

jsonGenerator.writeEndObject(); // end nested object 

jsonGenerator.writeEndObject(); 

समाधान एक आवरण वस्तु का उपयोग कर:

@JsonAutoDetect 
public class Wrapper { 
    private transient InfoCollection data; // transient makes Jackson ignore this 

    public String getFieldA() { return data.info1.fieldA; } 
    public String getFieldB() { return data.info1.fieldB; } 
} 

बनाता है यही कारण है कि जैक्सन को देखने के केवल आप क्या चाहते हैं और आप इसे कैसे करना चाहते हैं।

List<Pair<String, Object>> data = collectFields(myInfoCollection); 

collectFields सभी क्षेत्रों की जांच करने और सूची जो या तो एक कहते हैं आदिम या, है, जहां field.getType().getName().startsWith("java.lang") या किसी अन्य नियमों के लिए सब कुछ जोड़ना चाहिए:

वैकल्पिक रूप से, उपयोग प्रतिबिंब रिकर्सिवली सभी क्षेत्रों और उनके नाम एकत्र करने के लिए आप की जरूरत है।

यदि फ़ील्ड एक संदर्भ है, तो collectFields() पर दोबारा कॉल करें।

जब आपके पास सूची है, तो परिणामों को लिखने के लिए बस एक लूप में jsonGenerator पर कॉल करें।

+0

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

+0

फ़ील्ड का पता लगाने के लिए प्रतिबिंब और एनोटेशन का उपयोग करें ताकि आप अपने जेनरेटर को कुछ सहायक तरीके/कक्षाओं से लिख सकें जो आपको कोड का पुन: उपयोग करने की अनुमति देते हैं। –

+0

वैकल्पिक रूप से, एक रैपर क्लास बनाएं जो आपको एक एपीआई देता है जो जैक्सन को आउटपुट के करीब है। –

8

writeFieldName("allInfo") पर कॉल करने के बजाय आपको writeObjectFieldStart("allInfo") पर कॉल करना चाहिए क्योंकि "allInfo" एक और JSON ऑब्जेक्ट है। तो अपने कस्टम serializer निम्नलिखित तरीके से दिखना चाहिए:

public void serialize(InfoCollection infoCollection, JsonGenerator jgen, SerializerProvider provider) throws IOException{ 
    jgen.writeStartObject(); 
    jgen.writeObjectFieldStart("allInfo"); 
    jgen.writeObjectField("fieldA", infoCollection.getInfo1().getFieldA()); 
    jgen.writeObjectField("fieldB", infoCollection.getInfo2().getFieldB()); 
    jgen.writeEndObject(); 
    jgen.writeEndObject(); 
} 

या आप एनोटेशन आधारित दृष्टिकोण की कोशिश कर सकते हैं: (। आप इस के लिए काम करने के लिए SerializationConfig.Feature.WRAP_ROOT_VALUE सुविधा को सक्षम करने की आवश्यकता है Serialization features देखें)

@JsonRootName("allInfo") 
public class InfoCollection { 
    @JsonUnwrapped 
    private InfoType1 info1; 
    @JsonUnwrapped 
    private InfoType2 info2; 

    /* getters, setters */ 
} 

+0

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

+0

आप इसे एनोटेशन के साथ भी कर सकते हैं, लेकिन यह कस्टम धारावाहिक के रूप में लचीला नहीं है। मैंने एनोटेशन आधारित उदाहरण के साथ जवाब अपडेट किया है। – wajda