2011-07-30 12 views
5

मैं MOXY JAXB उपयोग करने के लिए एक वर्ग के एक जो दिखता है क्रमानुसार करने कोशिश कर रहा हूँ की तरह:XmlAdapter और XmlIDREF Moxy JAXB में

@XmlAccessorType(XmlAccessType.NONE) 
@XmlRootElement 
public class A { 
    private Map<Foo, Bar> fooBar = new HashMap<Foo, Bar>(); 
    private Set<Foo> foos = new HashSet<Foo>(); 

    @XmlJavaTypeAdapter(FooBarMapAdapter.class) 
    public Map<Foo, Bar> getFooBar() { 
     return fooBar; 
    } 

    public void setFooBar(Map<Foo, Bar> fooBar) { 
     this.fooBar = fooBar; 
    } 

    @XmlElement 
    public Set<Foo> getFoos() { 
     return foos; 
    } 

    public void setFoos(Set<Foo> foos) { 
     this.foos = foos; 
    } 
} 

मुद्दा यह है कि फू "कम महत्वपूर्ण चीज़ें" में वस्तुओं क्षेत्रों उन का सुपरसेट कर रहे हैं fooBar मानचित्र में। इसलिए मैं "foos" सूची के प्रमुख तत्वों को "foos" सूची में संबंधित तत्वों को "लिंक" करना चाहता हूं। मैं इस की कोशिश की है XmlID और XmlIDREF एनोटेशन का उपयोग:

@XmlAccessorType(XmlAccessType.NONE) 
public class Foo { 
    private String xmlId; 

    @XmlID 
    @XmlAttribute 
    public String getXmlId() { 
     return xmlId; 
    } 

    public void setXmlId(String xmlId) { 
     this.xmlId = xmlId; 
    } 
} 


@XmlAccessorType(XmlAccessType.NONE) 
public class Bar { 
    // Some code... 
} 

तब मेरे XmlAdapter में मैं अनुकूलित नक्शा प्रविष्टियों 'foo वस्तु पर एक XmlIDREF एनोटेशन का उपयोग करने की कोशिश की है:

public class FooBarMapAdapter extends 
     XmlAdapter<FooBarMapAdapter.FooBarMapType, Map<Foo, Bar>> { 
    public static class FooBarMapType { 
     public List<FooBarMapEntry> entries = new ArrayList<FooBarMapEntry>(); 
    } 

    @XmlAccessorType(XmlAccessType.NONE) 
    public static class FooBarMapEntry { 
     private Foo foo; 
     private Bar bar; 

     @XmlIDREF 
     @XmlAttribute 
     public Foo getFoo() { 
      return foo; 
     } 

     public void setFoo(Foo foo) { 
      this.foo = foo; 
     } 

     @XmlElement 
     public Bar getBar() { 
      return bar; 
     } 

     public void setBar(Bar bar) { 
      this.bar = bar; 
     } 
    } 

    @Override 
    public FooBarMapType marshal(Map<Foo, Bar> map) throws Exception { 
     FooBarMapType fbmt = new FooBarMapType(); 
     for (Map.Entry<Foo, Bar> e : map.entrySet()) { 
      FooBarMapEntry entry = new FooBarMapEntry(); 
      entry.setFoo(e.getKey()); 
      entry.setBar(e.getValue()); 
      fbmt.entries.add(entry); 
     } 
     return fbmt; 
    } 

    @Override 
    public Map<Foo, Bar> unmarshal(FooBarMapType fbmt) throws Exception { 
     Map<Foo, Bar> map = new HashMap<Foo, Bar>(); 
     for (FooBarMapEntry entry : fbmt.entries) { 
      map.put(entry.getFoo(), entry.getBar()); 
     } 
     return map; 
    } 
} 

कोड प्रमुखता जब उम्मीद के रूप में ऊपर काम करने और निम्न XML का उत्पादन किया जाता है:

<?xml version="1.0" encoding="UTF-8"?> 
<a> 
    <fooBar> 
     <entries foo="nr1"> 
     <bar/> 
     </entries> 
    </fooBar> 
    <foos xmlId="nr1"/> 
</a> 

परीक्षण unmarshal के लिए, मैं निम्नलिखित परीक्षण कोड का उपयोग कर रहा:

+०१२३५१६४१०६

{[email protected]} 

है, नक्शे में महत्वपूर्ण के रूप में इस्तेमाल फू वस्तु रिक्त है:

public class Test { 
    public static void main(String[] args) throws Exception { 
     A a = new A(); 

     Map<Foo, Bar> map = new HashMap<Foo, Bar>(); 
     Foo foo = new Foo(); 
     foo.setXmlId("nr1"); 
     Bar bar = new Bar(); 
     map.put(foo, bar); 
     a.setFooBar(map); 
     a.setFoos(map.keySet()); 

     final File file = new File("test.xml"); 
     if (!file.exists()) 
      file.createNewFile(); 
     FileOutputStream fos = new FileOutputStream(file); 

     JAXBContext jc = JAXBContext.newInstance(A.class); 
     Marshaller m = jc.createMarshaller(); 
     m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 
     m.marshal(a, fos); 

     FileInputStream fis = new FileInputStream(file); 
     Unmarshaller um = jc.createUnmarshaller(); 
     A newA = (A) um.unmarshal(fis); 

     System.out.println(newA.getFooBar()); 
    } 
} 

इस कोड (मेरे लिए) अनपेक्षित परिणाम पैदा करता है। यदि मैं नक्शा एडाप्टर बदलता हूं और आईडी संदर्भ का उपयोग करने के बजाय दो बार Foo ऑब्जेक्ट को मार्शल करता हूं, तो मुझे यह शून्य सूचक नहीं मिलता है।

मैं जेएक्सबी-आरआई का उपयोग करके Google पर इस बारे में कुछ पोस्ट ढूंढने में सक्षम हूं, जहां समस्या को http://weblogs.java.net/blog/2005/08/15/pluggable-ididref-handling-jaxb-20 पर वर्णित आईडीआरसोल्वर लिखने में हल किया जा सकता है। दुर्भाग्य से मैं MOXY JAXB JavaDoc में ऐसी कक्षा के बारे में कोई जानकारी नहीं पा रहा हूं। वैकल्पिक हल ब्लेज Doughan जवाब से के लिए

सुझाव, मुझे एहसास हुआ है कि यह JAXB की MOXY कार्यान्वयन में एक बग है। मैं इस बग के लिए एक (बदसूरत) कामकाज करने में सक्षम हूं। विचार यह है कि XMLAdapter का उपयोग करने के बजाय मानचित्र को इसकी परिभाषित कक्षा के अंदर "रूपांतरित" किया जाता है। कक्षा एक अब लगता है कि:

@XmlAccessorType(XmlAccessType.NONE) 
@XmlRootElement 
public class A { 
    private Map<Foo, Bar> fooBar = new HashMap<Foo, Bar>(); 
    private Set<Foo> foos = new HashSet<Foo>(); 

    // Due to a bug a XMLAdapter approch is not possible when using XmlIDREF. 
    // The map is mapped by the wrapper method getXmlableFooBarMap. 
    // @XmlJavaTypeAdapter(FooBarMapAdapter.class) 
    public Map<Foo, Bar> getFooBar() { 
     return fooBar; 
    } 

    public void setFooBar(Map<Foo, Bar> fooBar) { 
     this.fooBar = fooBar; 
    } 

    @XmlElement 
    public Set<Foo> getFoos() { 
     return foos; 
    } 

    public void setFoos(Set<Foo> foos) { 
     this.foos = foos; 
    } 

    // // WORKAROUND FOR JAXB BUG ///// 
    private List<FooBarMapEntry> mapEntries; 

    @XmlElement(name = "entry") 
    public List<FooBarMapEntry> getXmlableFooBarMap() { 
     this.mapEntries = new LinkedList<FooBarMapEntry>(); 
     if (getFooBar() == null) 
      return mapEntries; 

     for (Map.Entry<Foo, Bar> e : getFooBar().entrySet()) { 
      FooBarMapEntry entry = new FooBarMapEntry(); 
      entry.setFoo(e.getKey()); 
      entry.setBar(e.getValue()); 
      mapEntries.add(entry); 
     } 

     return mapEntries; 
    } 

    public void setXmlableFooBarMap(List<FooBarMapEntry> entries) { 
     this.mapEntries = entries; 
    } 

    public void transferFromListToMap() { 
     fooBar = new HashMap<Foo, Bar>(); 
     for (FooBarMapEntry entry : mapEntries) { 
      fooBar.put(entry.getFoo(), entry.getBar()); 
     } 
    } 
} 

unmarshal के बाद, transferFromListToMap-विधि अब कहा जाता है की जरूरत है। तो निम्नलिखित लाइन जोड़ा जाना चाहिए तुरंत बाद Newa के संदर्भ में प्राप्त किया जाता है:

newA.transferFromListToMap(); 

एक अच्छे वैकल्पिक हल/बग समाधान के लिए कोई सुझाव की सराहना की होगी :)।

+1

मैं अपनी कक्षा पर एक \ @XmlJavaTypeAdapter एनोटेशन रखने वाली किसी ऑब्जेक्ट पर \ @XmlIDREF विधि को मार्शल करने में समस्या का सामना कर रहा हूं। यहां ऑब्जेक्ट की आईडी निर्दिष्ट करने के बजाय पूरी वस्तु मार्शल हो जाती है। –

उत्तर

1

नोट: मैं EclipseLink JAXB (MOXy) लीड हूं।

मैं मुद्दा यह है कि आप देख रहे हैं इस बात की पुष्टि करने में सक्षम है: कारण MOXY XmlAdapter प्रसंस्करण के लिए

क्यों जारी करना

मुद्दा है हो रहा है @XmlIDREF तर्क को संसाधित करने से पहले तर्क। मोक्सी एक्सएमएल दस्तावेज़ का एक ही पास करता है, और @XmlIDREF संबंधों को अंत में संसाधित किया जाता है ताकि यह सुनिश्चित किया जा सके कि सभी संदर्भित वस्तुओं का निर्माण किया गया है (जैसा संदर्भ संदर्भित वस्तु से पहले हो सकता है, जैसा कि इस मामले में है)।

मैं इस मुद्दे पर एक समाधान पोस्ट करने का प्रयास करूंगा, और आप उपरोक्त बग का उपयोग करके इस मुद्दे पर हमारी प्रगति को ट्रैक कर सकते हैं।

+0

उत्तर के लिए धन्यवाद। मैंने अपने प्रश्न में एक समाधान के लिए एक सुझाव जोड़ा है। –

+2

मैंने भी इस बग को मारा। क्या भविष्य में कोई प्रगति होगी? या क्या यह हल करने का कोई और तरीका है। ईमानदारी से ईसाई। –

+0

वही, मेरे एक्सएमएलएडाप्टर का कॉन्फ़िगर किया गया उदाहरण मार्शलर को पास किया गया है जब @XmlIDREF एनोटेशन वाले फ़ील्ड को मार्शल करते समय अनदेखा किया जाता है। यह सूर्य कार्यान्वयन के साथ पूरी तरह से काम कर रहा था। – rochb