[Java] JAXB द्वारा उत्पन्न कोई @XmlRootElement नहीं


Answers

जो कुछ पहले से ही बताए गए हैं या संकेत दिए हैं, उन नियमों को बांधने के लिए, जिन नियमों से @XmlRootElement निर्णय लेता है कि जेनरेट क्लास पर @XmlRootElement एनोटेशन डालना है या नहीं, यह @XmlRootElement नहीं है ( इस आलेख को देखें )।

@XmlRootElement मौजूद है क्योंकि JAXB रनटाइम को किसी दिए गए ऑब्जेक्ट को मार्शल / @XmlRootElement करने के लिए कुछ विशेष जानकारी की आवश्यकता होती है, विशेष रूप से एक्सएमएल तत्व का नाम और नामस्थान। आप मार्शलर को बस किसी पुरानी वस्तु को पास नहीं कर सकते हैं। @XmlRootElement इस जानकारी को प्रदान करता है।

एनोटेशन सिर्फ एक सुविधा है, हालांकि - जेएक्सबी को इसकी आवश्यकता नहीं है। विकल्प JAXBElement ऑब्जेक्ट्स का उपयोग JAXBElement है, जो एक ही जानकारी को @XmlRootElement रूप में प्रदान करता है, लेकिन एक एनोटेशन के बजाए किसी ऑब्जेक्ट के रूप में।

हालांकि, JAXBElement ऑब्जेक्ट्स निर्माण के लिए अजीब हैं, क्योंकि आपको XML तत्व नाम और नामस्थान जानने की आवश्यकता है, जो आमतौर पर व्यावसायिक तर्क नहीं करता है।

शुक्र है, जब एक्सजेसी एक वर्ग मॉडल उत्पन्न करता है, तो यह ObjectFactory नामक एक वर्ग भी उत्पन्न करता है। यह आंशिक रूप से JAXBElement साथ पिछड़ा संगतता के लिए है, लेकिन यह JAXBElement लिए जेनरेट फैक्ट्री विधियों को रखने के लिए एक जगह के रूप में भी है जो आपके स्वयं के ऑब्जेक्ट्स के आसपास JAXBElement रैपर बनाते हैं। यह आपके लिए एक्सएमएल नाम और नेमस्पेस को संभालता है, इसलिए आपको इसके बारे में चिंता करने की आवश्यकता नहीं है। आपको केवल ObjectFactory को ढूंढने के लिए ObjectFactory विधियों (और बड़ी स्कीमा के लिए, उनमें से सैकड़ों हो सकते हैं) को देखने की आवश्यकता है।

Question

मैं एफपीएमएल (फिनानियल प्रोडक्ट्स मार्कअप लैंग्वेज) संस्करण 4.5 से जावा कक्षाएं उत्पन्न करने की कोशिश कर रहा हूं। कोड का एक टन उत्पन्न होता है, लेकिन मैं इसका उपयोग नहीं कर सकता। एक साधारण दस्तावेज़ को क्रमबद्ध करने का प्रयास करते हुए मुझे यह मिलता है:

javax.xml.bind.MarshalException
  - with linked exception: [com.sun.istack.SAXException2: unable
  to marshal type
  "org.fpml._2008.fpml_4_5.PositionReport"
  as an element because it is missing an
  @XmlRootElement annotation]

वास्तव में कोई कक्षा में @XmlRootElement एनोटेशन नहीं है, तो मैं गलत क्या कर सकता हूं? मैं xjc (JAXB 2.1) को fpml-main-4-5.xsd पर इंगित कर रहा हूं, जिसमें सभी प्रकार शामिल हैं।




एक @XmlRootElement बिल्ड के साथ, आप @XmlRootElement एनोटेशन जोड़ सकते हैं

" jaxb2-basics-annotate " प्लग-इन के साथ।

अधिक जानकारी देखें: देखें

जेएक्सबी का उपयोग कर एक्सएमएल स्कीमा से कक्षाएं उत्पन्न करने के लिए मेवेन को कॉन्फ़िगर करें

और जेएक्सबी एक्सजेसी कोड पीढ़ी




जैसा कि उपर्युक्त उत्तरों में से एक में संकेत दिया गया है, आपको एक्सएसडी में अपने रूट तत्व पर XMLRootElement नहीं मिलेगा, इसका प्रकार नामित प्रकार के रूप में परिभाषित किया गया है, क्योंकि उस नाम का प्रकार आपके एक्सएसडी में कहीं और इस्तेमाल किया जा सकता है। इसे एक अज्ञात प्रकार का मजाक करने का प्रयास करें, यानी इसके बजाए:

<xsd:element name="myRootElement" type="MyRootElementType" />

<xsd:complexType name="MyRootElementType">
...
</xsd:complexType>

आप होंगे:

<xsd:element name="myRootElement">
    <xsd:complexType>
    ...
    <xsd:complexType>
</xsd:element>



इसे हल करने के लिए आपको wsimport के साथ संकलित करने के लिए पहले xml बाध्यकारी कॉन्फ़िगर करना चाहिए, जेनरेटप्रॉपर्टी को झूठी के रूप में सेट करना चाहिए।

     <jaxws:bindings wsdlLocation="LOCATION_OF_WSDL"
      xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
      xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" 
      xmlns:xs="http://www.w3.org/2001/XMLSchema"
      xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
      xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
         <jaxws:enableWrapperStyle>false</jaxws:enableWrapperStyle>
    <jaxws:bindings  node="wsdl:definitions/wsdl:types/xs:schema[@targetNamespace='NAMESPACE_OF_WSDL']">
      <jxb:globalBindings xmlns:jxb="http://java.sun.com/xml/ns/jaxb" xmlns:xs="http://www.w3.org/2001/XMLSchema">
            <xjc:generateElementProperty>false</xjc:generateElementProperty> 
      </jxb:globalBindings>
  </jaxws:bindings>
</jaxws:bindings>



JAXBElement wrappers उन मामलों के लिए काम करता है जहां JAXB द्वारा कोई @XmlRootElement उत्पन्न नहीं @XmlRootElement है। ये रैपर maven-jaxb2-plugin द्वारा उत्पन्न maven-jaxb2-plugin क्लास में उपलब्ध हैं। उदाहरण के लिए:

     public class HelloWorldEndpoint {
        @PayloadRoot(namespace = NAMESPACE_URI, localPart = "person")
        @ResponsePayload
        public JAXBElement<Greeting> sayHello(@RequestPayload JAXBElement<Person> request) {

        Person person = request.getValue();

        String greeting = "Hello " + person.getFirstName() + " " + person.getLastName() + "!";

        Greeting greet = new Greeting();
        greet.setGreeting(greeting);

        ObjectFactory factory = new ObjectFactory();
        JAXBElement<Greeting> response = factory.createGreeting(greet);
        return response;
      }
 }



यह हमारे लिए भी काम नहीं कर रहा है। लेकिन हमें व्यापक रूप से उद्धृत लेख मिला जो कुछ पृष्ठभूमि जोड़ता है ... मैं इसे अगले व्यक्ति के लिए यहां लिंक करूंगा: http://weblogs.java.net/blog/kohsuke/archive/2006/03/why_does_jaxb_p.html




जो का जवाब (जो जून 26 '0 9 17:26 पर) यह मेरे लिए करता है। सरल जवाब यह है कि यदि आप एक JAXBElement को मार्शल करते हैं तो @XmlRootElement एनोटेशन की अनुपस्थिति कोई समस्या नहीं है। जिस चीज ने मुझे भ्रमित किया है वह है जेनरेट ऑब्जेक्ट फैक्ट्री में 2 createMyRootElement विधियां हैं - पहले कोई पैरामीटर नहीं लेता है और अनचाहे ऑब्जेक्ट देता है, दूसरा अनचाहे ऑब्जेक्ट लेता है और इसे जेएक्सबीमेंट में लपेटता है, और यह बताता है कि जेएक्सबीमेंट ठीक काम करता है। यहां उपयोग किया गया मूल कोड है (मैं इसके लिए नया हूं, इसलिए क्षमा करें अगर कोड इस उत्तर में सही ढंग से स्वरूपित नहीं है), बड़े पैमाने पर लिंक टेक्स्ट से प्राप्त किया गया है :

ObjectFactory objFactory = new ObjectFactory();
MyRootElement root = objFactory.createMyRootElement();
...
// Set root properties
...
if (!writeDocument(objFactory.createMyRootElement(root), output)) {
    System.err.println("Failed to marshal XML document");
}
...

private boolean writeDocument(JAXBElement document, OutputStream output) {

  Class<?> clazz = document.getValue().getClass();
  try {
    JAXBContext context =
        JAXBContext.newInstance(clazz.getPackage().getName());
    Marshaller m = context.createMarshaller();
    m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
    m.marshal(document, output);
    return true;

  } catch (JAXBException e) {
    e.printStackTrace(System.err);
    return false;
  }
}



Unmarshalling के लिए @XmlRootElement की आवश्यकता नहीं है - अगर कोई Unmarshaller # unmarshall के 2 पैरामीटर फॉर्म का उपयोग करता है।

तो, अगर करने के बजाय:

UserType user = (UserType) unmarshaller.unmarshal(new StringReader(responseString));

एक करना चाहिए:

JAXBElement<UserType> userElement = unmarshaller.unmarshal(someSource, UserType.class);
UserType user = userElement.getValue();

बाद वाले कोड को UserType क्लास स्तर पर @XmlRootElement एनोटेशन की आवश्यकता नहीं होगी।




जैसा कि आप जानते हैं कि ऑब्जेक्ट फैक्ट्री () का उपयोग करना है। यहां कोड का एक नमूना है जो मेरे लिए काम करता है :)

ObjectFactory myRootFactory = new ObjectFactory();

MyRootType myRootType = myRootFactory.createMyRootType();

try {

        File file = new File("./file.xml");
        JAXBContext jaxbContext = JAXBContext.newInstance(MyRoot.class);
        Marshaller jaxbMarshaller = jaxbContext.createMarshaller();

        //output pretty printed
        jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

        JABXElement<MyRootType> myRootElement = myRootFactory.createMyRoot(myRootType);

        jaxbMarshaller.marshal(myRootElement, file);
        jaxbMarshaller.marshal(myRootElement, System.out);

    } catch (JAXBException e) {
        e.printStackTrace();
    }



दो दिनों के लिए संघर्ष करने के बाद मुझे समस्या का समाधान मिला। आप ऑब्जेक्ट फैक्ट्री क्लास का उन वर्गों के लिए कामकाज का उपयोग कर सकते हैं जिनके पास @XmlRootElement नहीं है। ऑब्जेक्ट फैक्ट्री ने JAXBElement के चारों ओर लपेटने के तरीकों को अधिभारित किया है। विधि: 1 ऑब्जेक्ट और विधि का सरल निर्माण करता है : 2 ऑब्जेक्ट को @JAXBElement से लपेट देगा । हमेशा उपयोग करने के लिए विधि: 2 javax.xml.bind.MarshalException से बचने के लिए - लिंक किए गए अपवाद के साथ एक @XmlRootElement एनोटेशन गुम है

विधि: 1

public GetCountry createGetCountry() {
        return new GetCountry();
    }

विधि: 2

 @XmlElementDecl(namespace = "my/name/space", name = "getCountry")
 public JAXBElement<GetCountry> createGetCountry(GetCountry value) {
        return new JAXBElement<GetCountry>(_GetCountry_QNAME, GetCountry.class, null, value);
    }

वर्किंग कोड नमूना:

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
WebServiceTemplate springWSTemplate = context.getBean(WebServiceTemplate.class);

GetCountry request = new GetCountry();
request.setGuid("1f3e1771-3049-49f5-95e6-dc3732c3227b");

JAXBElement<GetCountryResponse> jaxbResponse = (JAXBElement<GetCountryResponse>)springWSTemplate .marshalSendAndReceive(new ObjectFactory().createGetCountry(request));

GetCountryResponse response = jaxbResponse.getValue();



अगर इस समस्या का मेरा अनुभव किसी को यूरेका देता है! पल .. मैं निम्नलिखित जोड़ दूंगा:

मुझे यह समस्या भी मिल रही थी, जब मैंने इंटेलिजे के "इंस्टेंस दस्तावेज़ से xsd जेनरेट करें" मेनू विकल्प का उपयोग करके जेएसडी फ़ाइल का उपयोग किया था।

जब मैंने इस टूल के सभी डिफ़ॉल्ट को स्वीकार किया, तो उसने एक एक्सएसडी फ़ाइल जेनरेट की जो @XmlRootElement साथ प्रयोग किया जाता है, @XmlRootElement फाइलों को बिना @XmlRootElement साथ उत्पन्न किया जाता है। रनटाइम पर जब मैंने मार्शल की कोशिश की तो मुझे इस प्रश्न में चर्चा के समान अपवाद मिला।

मैं IntellJ टूल पर वापस गया, और "Desgin टाइप" ड्रॉप डाउन में डिफ़ॉल्ट विकल्प देखा (जो निश्चित रूप से मुझे समझ में नहीं आया .. और अभी भी अगर मैं ईमानदार नहीं हूं) था:

Desgin प्रकार:

"स्थानीय तत्व / वैश्विक जटिल प्रकार"

मैंने इसे बदल दिया

"स्थानीय तत्व / प्रकार"

, अब यह एक (काफी) अलग xsd उत्पन्न करता है, जिसने jaxb के साथ उपयोग किए जाने पर @XmlRootElement उत्पादन किया। यह नहीं कह सकता कि मैं इसमें और बाहर समझता हूं, लेकिन यह मेरे लिए काम करता है।




क्या आपने इस तरह अपना एक्सएसडी बदलने की कोशिश की?

<!-- create-logical-system -->
<xs:element name="methodCall">
  <xs:complexType>
    ...
  </xs:complexType>
</xs:element>



यह ऊपर से जुड़े ब्लॉग पोस्ट के निचले हिस्से में उल्लिखित है लेकिन यह मेरे लिए एक इलाज की तरह काम करता है:

Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(new JAXBElement<MyClass>(new QName("uri","local"), MyClass.class, myClassInstance), System.out);



एक्सएसडी में बेस प्रकारों के लिए @XmlRootElement क्लासेस कैसे उत्पन्न करें , इस से बाध्यकारी का उपयोग करके आप इस समस्या को ठीक कर सकते हैं ?

मेवेन के साथ एक उदाहरण यहां दिया गया है

        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>jaxb2-maven-plugin</artifactId>
            <version>1.3.1</version>
            <executions>
                <execution>
                    <id>xjc</id>
                    <goals>
                        <goal>xjc</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <schemaDirectory>src/main/resources/xsd</schemaDirectory>
                <packageName>com.mycompany.schemas</packageName>
                <bindingFiles>bindings.xjb</bindingFiles>
                <extension>true</extension>
            </configuration>
        </plugin>

यहां binding.xjb फ़ाइल सामग्री है

<?xml version="1.0"?>
<jxb:bindings version="1.0" xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
              xmlns:xjc= "http://java.sun.com/xml/ns/jaxb/xjc"
              jxb:extensionBindingPrefixes="xjc" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <jxb:bindings schemaLocation="path/to/myschema.xsd" node="/xs:schema">
        <jxb:globalBindings>
            <xjc:simple/>
        </jxb:globalBindings>
    </jxb:bindings>
</jxb:bindings>