2011-11-22 10 views
5

में विरासत मैं एक ऑब्जेक्ट को दूसरे से संदर्भित करने के लिए @XmlID और @XmlIDREF टैग का उपयोग कर रहा हूं। यह विरासत कक्षाओं के साथ भी जावा 6 में ठीक काम कर रहा था। मैंने जो उदाहरण कोड बनाया है, वह इस तरह दिखता है। बेस वर्ग प्रयुक्त टैग:एक्सएमएलआईडी/एक्सएमएलआईडीआरईएफ और नवीनतम जेएक्सबी संस्करण (जावा 7)

@XmlRootElement 
@XmlAccessorType(FIELD) 
public class Module { 
    Module() {} 

    @XmlIDREF 
    private Module other; 

    @XmlID 
    private String id; 

    public Module(String id, Module other) { 
     this.id = id; 
     this.other = other; 
    } 
} 

इनहेरिट की गई वर्ग:

कंटेनर इन कक्षाओं के लिए:

@XmlRootElement 
public class Script { 
    Script() {} 
    public Script(Collection<Module> modules) { 
     this.modules = modules; 
    } 

    @XmlElementWrapper 
    @XmlElementRef 
    Collection<Module> modules = new ArrayList<Module>(); 
} 

इस उदाहरण कोड चलाते समय:

public class JaxbTest { 

    private Script createScript() { 
     Module m1 = new Module("Module1", null); 
     Module m2 = new TheModule("Module2", m1, "featured module"); 
     Module m3 = new Module("Module3", m2); 
     return new Script(Arrays.asList(m1, m2, m3)); 
    } 

    private String marshal(Script script) throws Exception { 
     JAXBContext context = JAXBContext.newInstance(Module.class, Script.class, TheModule.class); 
     Writer writer = new StringWriter(); 
     context.createMarshaller().marshal(script, writer); 
     return writer.toString(); 
    } 

    private void runTest() throws Exception { 
     Script script = createScript(); 

     System.out.println(marshal(script)); 
    } 

    public static void main(String[] args) throws Exception { 
     new JaxbTest().runTest(); 
    } 
} 

मैं प्राप्त एक्सएमएल, जावा 6 में:

<script> 
    <modules> 
    <module> 
     <id>Module1</id> 
    </module> 
    <theModule> 
     <other>Module1</other> 
     <id>Module2</id> 
     <feature>featured module</feature> 
    </theModule> 
    <module> 
     <other>Module2</other> 
     <id>Module3</id> 
    </module> 
    </modules> 
</script> 

ध्यान दें कि एम 2 (TheModule उदाहरण) के संदर्भ में अपेक्षा के अनुरूप धारावाहिक है। लेकिन जब एक ही कोड जावा 7 (JAXB 2.2.4-1) के तहत चल रहा है मैं प्राप्त करते हैं:

<script> 
    <modules> 
    <module> 
     <id>Module1</id> 
    </module> 
    <theModule> 
     <other>Module1</other> 
     <id>Module2</id> 
     <feature>featured module</feature> 
    </theModule> 
    <module> 
     <other xsi:type="theModule" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
     <other>Module1</other> 
     <id>Module2</id> 
     <feature>featured module</feature> 
     </other> 
     <id>Module3</id> 
    </module> 
    </modules> 
</script> 

तो आप देख सकते हैं नवीनतम विरासत में मिला मॉड्यूल के लिए JAXB @XmlIDREF काम नहीं कर रहा पर!

उत्तर

2

यह उत्तर गलत है। इस पर भरोसा करने के बजाय JAXBContext.newInstance(...) के लिए प्रलेखन पढ़ें, this answer और नीचे दी गई टिप्पणियां देखें।


मुझे लगता है कि आप निम्नलिखित पंक्ति के साथ जेएक्सबी को भ्रमित करते हैं।

JAXBContext.newInstance(Module.class, Script.class, TheModule.class); 

आप यह कहना है कि आप एक्सएमएल प्रकार Script, Module और TheModule क्रमानुसार करने चाहते हैं। जेएक्सबी इस बाद के प्रकार की वस्तुओं को विशेष तरीके से व्यवहार करेगा, क्योंकि आपने पहले से ही अपनी बेस क्लास की आपूर्ति की है: इसमें एक भेदभावपूर्ण विशेषता है। इस तरह से इन दो प्रकारों को धारावाहिक एक्सएमएल में विभेदित किया जा सकता है।

Script और Module की आपूर्ति करने का प्रयास करें, के लिए बेस क्लास सभी मॉड्यूल।

JAXBContext.newInstance(Module.class, Script.class); 

वास्तव में, आप पूरी तरह से Module छोड़ सकते हैं। JAXB Script ऑब्जेक्ट में प्रकारों का अनुमान लगाएगा जो आप संदर्भ से क्रमबद्ध करने का प्रयास करते हैं।

इस व्यवहार का तरीका जावा 6 से संबंधित बिल्कुल नहीं है। यह उपयोग में जेएक्सबी कार्यान्वयन से संबंधित है (ठीक है, ठीक है, लगभग एक ही चीज़, मुझे पता है)। मेरी परियोजनाओं में मैं जेएक्सबी 2.2.4-1 का उपयोग करता हूं, जो इस मुद्दे को जावा 6 और 7 में भी उत्पन्न करता है।

ओह, और एक और बात: बजाय System.out करने के लिए एक StringWriter इसकी सामग्री बनाने और उस में वस्तुओं वास्ते, तो भेजने की आप stdout के लिए स्वरूपित एक्सएमएल भेजने के लिए निम्नलिखित का उपयोग कर सकते हैं।

Marshaller marshaller = context.createMarshaller(); 
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); 
marshaller.marshal(script, System.out); 

शायद यह आसानी से (थोड़ा छोटा) आगे परीक्षण कर सकता है।

+0

अपने जवाब के लिए धन्यवाद। मुझे कुछ शंकाए है। JAXBContext.newInstance (कक्षा ...) के लिए जावाडोक कहता है कि कॉलर को शीर्ष-स्तरीय कक्षाएं सूचीबद्ध करनी होंगी। "नया संदर्भ निर्दिष्ट सभी वर्गों को पहचान लेगा, लेकिन यह निर्दिष्ट कक्षाओं से सीधे/अप्रत्यक्ष रूप से संदर्भित ** किसी भी कक्षा को पहचानने के लिए ** स्थिर रूप से ** (एसआईसी!) को संदर्भित करेगा। संदर्भित कक्षाओं के उप-वर्ग और न ही @ एक्सएमएल ट्रांसिएंट संदर्भित कक्षाएं पंजीकृत नहीं हैं JAXBContext। "। यदि हम कॉन्स्टेंटिन के उदाहरण पर इस कथन को लागू करते हैं, तो वंशज वर्ग मॉड्यूल स्वतः खोज नहीं किया जाएगा। \ –

+0

@ एंडीमालकोव ऐसा लगता है कि आप सही हैं। मुझे बिल्कुल याद नहीं है कि अगर मैंने प्रश्न का उत्तर दिया, तो मैंने 'newInstance' के लिए प्रलेखन पढ़ा है, लेकिन मुझे याद है कि मैंने कुछ कोड की कोशिश की है और मैंने जो लिखा है उसे जांचना प्रतीत होता है। चूंकि ओपी ने किसी भी तरह से मेरे जवाब का जवाब नहीं दिया है, इसलिए मैं इसे पूरी तरह से भूल गया हूं। असल में मैं देख सकता हूं कि मैंने वास्तविक प्रश्न/समस्या का गलत व्याख्या किया है, इसलिए मेरा जवाब पूरी तरह से बंद है। मैं इसे प्रतिबिंबित करने के लिए अपना उत्तर अपडेट करूंगा। इनपुट के लिए धन्यवाद! –

0

यह जेएक्सबी में एक ज्ञात बग प्रतीत होता है। मुझे एक ही समस्या थी और इसे XmlIDRef का उपयोग न करके हल किया गया था, बल्कि एक कस्टम आईडी के साथ postDeserialize का उपयोग कर हल किया गया।

http://java.net/jira/browse/JAXB-870

मैं Kohányi रॉबर्ट के सुझाव का उपयोग नहीं कर सकता है:

यहाँ एक बग रिपोर्ट है। क्या यह आपके लिए काम करता है?

0

यदि आप अभी भी 2017 में जावा 7 के साथ फंस गए हैं, तो इसे रोकने के लिए एक आसान तरीका है। समस्या यह है कि जब XmlREFId के साथ serialiazing, जैक्सब उप-वर्गों का सामना नहीं कर सकता है। एक समाधान एडाप्टर का उपयोग करना है और उसी आईडी के साथ बेस क्लास का एक नया उदाहरण लौटाया जा सकता है क्योंकि एक धारावाहिक (केवल आईडी का उपयोग किया जाएगा, इसलिए हमें अन्य क्षेत्रों से परेशान करने की आवश्यकता नहीं है):

public class ModuleXmlAdapter extends XmlAdapter<Module, Module> { 
    @Override 
    public Module unmarshal(Module v) { 
     // there is no problem with deserializing - return as is 
     return v; 
    } 

    @Override 
    public Module marshal(Module v) { 
     if (v == null) { 
      return null; 
     } 
     // here is the trick: 
     return new Module(v.getId(), null); 
    } 
} 

फिर, सिर्फ इतना है कि अनुकूलक जहाँ भी जरूरत का उपयोग करें:

public class Module { 
    @XmlIDREF 
    @XmlJavaTypeAdapter(ModuleXmlAdapter.class) 
    private Module other; 

    //... 
} 
संबंधित मुद्दे