2012-04-14 11 views
5

अद्यतन - नीचेजेएक्सबी एनोटेशन - मैं XmlIDRef तत्वों की सूची कैसे बना सकता हूं आईडी तत्व को तत्व निकाय पाठ के बजाय एक विशेषता के रूप में?

IDRefs पर संपादित देख/keyrefs JAXB एनोटेशन में संभव होने लगते हैं, लेकिन रेफरी तत्व पाठ किया जा रहा समाप्त होता है।

मैं रेफरी को तत्व की विशेषता मानना ​​चाहता हूं।

उदाहरण के लिए, इस ऑब्जेक्ट मॉडल दिया:

@XmlType 
public class Employee { 
    @XmlID 
    @XmlAttribute 
    String name; 
    @XmlAttribute 
    int years; 
    @XmlAttribute 
    String foo; 
} 

@XmlType 
public class Office { 
    @XmlAttribute 
    String name; 
    @XmlElementWrapper 
    @XmlElement(name = "employee") 
    List<Employee> employees; 
} 

@XmlRootElement 
public class Company { 
    @XmlElementWrapper 
    @XmlElement(name = "office") 
    List<Office> offices; 
    @XmlElementWrapper 
    @XmlElement(name = "employee") 
    List<Employee> employees; 
} 

मैं externalized एक्सएमएल प्रारूप चाहते हैं इस तरह लग रही अंत में:

<company> 
    <offices> 
     <office name="nyc"> 
      <employees> 
       <!--*** id ref to employee name ***--> 
       <employee ref="alice"/> 
       <employee ref="bob"/> 
      </employees> 
     </office> 
     <office name="sf"> 
      <employees> 
       <employee ref="connie"/> 
       <employee ref="daphne"/> 
      </employees> 
     </office> 
    </offices> 
    <employees> 
     <!-- *** name is the id *** --> 
     <employee name="alice" years="3" foo="bar"/> 
     <employee name="bob" years="3" foo="bar"/> 
     <employee name="connie" years="3" foo="bar"/> 
     <employee name="daphne" years="3" foo="bar"/> 
    </employees> 
</company> 

इसके बजाय, सबसे अच्छा मैं कर सकता हूँ यह है (जावा कोड में ऊपर सूचीबद्ध एनोटेशन के साथ):

<company> 
    <offices> 
     <office name="nyc"> 
      <employees> 
       <employee>alice</employee> 
       <employee>bob</employee> 
      </employees> 
     </office> 
     <office name="sf"> 
      <employees> 
       <employee>connie</employee> 
       <employee>daphne</employee> 
      </employees> 
     </office> 
    </offices> 
    <employees> 
     <employee name="alice" years="3" foo="bar"/> 
     <employee name="bob" years="3" foo="bar"/> 
     <employee name="connie" years="3" foo="bar"/> 
     <employee name="daphne" years="3" foo="bar"/> 
    </employees> 
</company> 

क्या कोई तरीका है कि मैं idref को मजबूर कर सकता हूं तत्व बॉडी टेक्स्ट की बजाय कर्मचारी की विशेषता होने का मूल्य? मुझे पता है कि मैं इसे एक्सएमएल स्कीमा के साथ कर सकता हूं, लेकिन यदि संभव हो तो मैं एनोटेशन पर टिकना चाहूंगा।

धन्यवाद।

संपादित करें लगभग काम करता है, लेकिन यह कुछ परिस्थितियों में काफी काम नहीं करता है।

unmarshalling विफल रहता है अगर "कार्यालय" तत्व पहले (xml फ़ाइल में) "कर्मचारी" तत्वों का उल्लेख करते हैं जो कार्यालय संदर्भ हैं। कर्मचारी संदर्भ नहीं पाए जाते हैं, और कर्मचारी रिफ रैपर में एक शून्य कर्मचारी वस्तु है। यदि "कर्मचारी" पहले हैं, तो यह काम करता है।

यह एक समस्या का इतना अधिक नहीं होगा, लेकिन मार्शल विधि पहले "कार्यालय" रखेगी, ताकि अनचाहे करने की कोशिश की जा रही है जो अभी तक खराब हो गया है।

संपादित करें 2 टिप्पणी में टोरियस 'उत्तर में ऑर्डरिंग समस्या हल होती है।

उत्तर

4

समाधान एक XmlAdapter जो एक नए प्रकार, EmployeeRef, जो एक्सएमएल आईडी रेफरी मैप करने के लिए कैसे निर्दिष्ट करता है का एक उदाहरण में एक Employee लपेटता उपयोग करने के लिए है:

@XmlType 
public class Office { 

    @XmlAttribute 
    String name; 

    @XmlElementWrapper 
    @XmlElement(name="employee") 
    @XmlJavaTypeAdapter(EmployeeAdapter.class) // (un)wraps Employee 
    List<Employee> employees; 
} 

@XmlType 
public class EmployeeRef { 

    @XmlIDREF 
    @XmlAttribute(name="ref") 
    Employee employee; 

    public EmployeeRef() { 
    } 

    public EmployeeRef(Employee employee) { 
     this.employee = employee; 
    } 
} 

public class EmployeeAdapter extends XmlAdapter<EmployeeRef, Employee> { 

    @Override 
    public EmployeeRef marshal(Employee employee) throws Exception { 
     return new EmployeeRef(employee); 
    } 

    @Override 
    public Employee unmarshal(EmployeeRef ref) throws Exception { 
     return ref.employee; 
    } 
} 

गुड लक।

+0

yup, यह चाल है। धन्यवाद। – marathon

+0

ठीक है, यह कुछ (अधिकांश) परिस्थितियों में काफी काम नहीं करता है। – marathon

+1

ऊपर संपादित करें देखें '@XmlType (propOrder = {"staff", "office"} के साथ' कंपनी' क्लास को एनोटेट करें) 'मार्शलिंग के दौरान वांछित क्रम को मजबूर करने के लिए। – Torious

2

नोट: मैं EclipseLink JAXB (MOXy) लीड और JAXB (JSR-222) विशेषज्ञ समूह का सदस्य हूं।

नीचे एक उदाहरण है कि यह @XmlPath एनोटेशन का लाभ उठाकर MOXy के साथ कैसे किया जा सकता है। bug के कारण, आपको 17 मई, 2012 से शुरू होने वाले एक ग्रहण लिंक 2.4.0 रात का लेबल उपयोग करने की आवश्यकता होगी। यह फ़िक्स EclipseLink 2.3.3 (18 मई, 2012 से शुरू) स्ट्रीम में भी जोड़ा जा सकता है।employees संपत्ति पर

कार्यालय

आप पाने के लिए @XmlPath एनोटेशन के साथ संयोजन में @XmlIDREF एनोटेशन का उपयोग कर सकते हैं: आप निम्न स्थान से एक रात लेबल डाउनलोड कर सकते हैं वांछित मैपिंग। @XmlIDREF वस्तु के बजाए एक विदेशी कुंजी लिखने के लिए जेएक्सबी कार्यान्वयन को बताता है।

package forum10150263; 

import java.util.List; 
import javax.xml.bind.annotation.*; 
import org.eclipse.persistence.oxm.annotations.XmlPath; 

@XmlType 
public class Office { 
    @XmlAttribute 
    String name; 

    @XmlPath("employees/employee/@ref") 
    @XmlIDREF 
    List<Employee> employees; 
} 

कर्मचारी

समकक्ष @XmlIDREF को @XmlID है। @XmlID किसी ऑब्जेक्ट के लिए प्राथमिक कुंजी निर्दिष्ट करने के लिए उपयोग किया जाता है।

package forum10150263; 

import javax.xml.bind.annotation.*; 

@XmlType 
public class Employee { 
    @XmlID 
    @XmlAttribute 
    String name; 

    @XmlAttribute 
    int years; 

    @XmlAttribute 
    String foo; 
} 

कंपनी

प्रत्येक वस्तु @XmlIDREF तंत्र के माध्यम से संदर्भित भी एक रोकथाम संबंध द्वारा संदर्भित किया जाना चाहिए। इस उदाहरण में यह employees संपत्ति द्वारा पूरा किया जाता है।

package forum10150263; 

import java.util.List; 
import javax.xml.bind.annotation.*; 

@XmlRootElement 
public class Company { 
    @XmlElementWrapper 
    @XmlElement(name = "office") 
    List<Office> offices; 

    @XmlElementWrapper 
    @XmlElement(name = "employee") 
    List<Employee> employees; 
} 

jaxb.properties

MOXY अपने JAXB प्रदाता के रूप में निर्दिष्ट करने के लिए आप निम्न लिखित प्रविष्टि के साथ अपने डोमेन मॉडल के रूप में एक ही पैकेज में jaxb.properties नाम की एक फ़ाइल जोड़ने की जरूरत है (Specifying EclipseLink MOXy as Your JAXB Provider देखें)

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory 

डेमो

मानक जेएक्सबी एपीआई का उपयोग एक्सएमएलशेलिंग/एक्सएमएलएलिंग के लिए किया जाता है।

package forum10150263; 

import java.io.File; 
import javax.xml.bind.*; 

public class Demo { 

    public static void main(String[] args) throws Exception { 
     JAXBContext jc = JAXBContext.newInstance(Company.class); 

     Unmarshaller unmarshaller = jc.createUnmarshaller(); 
     File xml = new File("src/forum10150263/input.xml"); 
     Company company = (Company) unmarshaller.unmarshal(xml); 

     Marshaller marshaller = jc.createMarshaller(); 
     marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 
     marshaller.marshal(company, System.out); 
    } 

} 

input.xml/आउटपुट

<?xml version="1.0" encoding="UTF-8"?> 
<company> 
    <offices> 
     <office name="nyc"> 
     <employees> 
      <employee ref="alice"/> 
      <employee ref="bob"/> 
     </employees> 
     </office> 
     <office name="sf"> 
     <employees> 
      <employee ref="connie"/> 
      <employee ref="daphne"/> 
     </employees> 
     </office> 
    </offices> 
    <employees> 
     <employee name="alice" years="3" foo="bar"/> 
     <employee name="bob" years="3" foo="bar"/> 
     <employee name="connie" years="3" foo="bar"/> 
     <employee name="daphne" years="3" foo="bar"/> 
    </employees> 
</company> 

अधिक जानकारी के लिए