Frage

Ich versuche, Java-Klassen aus der FpML (Finanial Products Markup Language) Version 4.5 zu erzeugen. Eine Tonne Code erzeugt, aber ich kann es nicht verwenden. Der Versuch, ein einfaches Dokument, das ich diese bekommen zu serialisiert:

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]

In der Tat keine classses die @XmlRootElement Anmerkung haben, so was kann ich falsch machen ?. Ich zeige xjc (JAXB 2.1) FpML-main-4-5.xsd, die dann alle Arten enthält.

War es hilfreich?

Lösung

binden zusammen, was andere haben bereits erwähnt oder angedeutet, die Regeln, nach denen JAXB XJC entscheidet, ob die @XmlRootElement Anmerkung auf einer generierten Klasse zu setzen ist nicht trivial ( sehen dieser Artikel ).

@XmlRootElement existiert, weil die JAXB Laufzeit bestimmte Informationen benötigt, um ein bestimmtes Objekt zu Marschall / Abstellungs, speziell die XML-Element Namen und Namespace. Sie können einfach nicht alle alten Objekt an den Marshaller passieren. @XmlRootElement stellt diese Informationen.

Die Anmerkung ist nur eine Bequemlichkeit, aber - JAXB es nicht erfordert. Die Alternative zu ist JAXBElement Wrapper-Objekte zu verwenden, die die gleichen Informationen wie @XmlRootElement bieten, sondern in Form eines Objekts, anstatt eine Anmerkung.

Allerdings sind JAXBElement Objekte umständlich zu konstruieren, da Sie das XML-Element Namen und Namespace wissen müssen, die Business-Logik in der Regel nicht der Fall ist.

Zum Glück, wenn XJC ein Klassenmodell erzeugt, erzeugt er auch eine Klasse namens ObjectFactory. Dies ist zum Teil dort für die Abwärtskompatibilität mit JAXB v1, aber es ist dort auch als Ort für XJC generiert Factory-Methoden setzen die JAXBElement Wrapper um eigene Objekte erstellen. Er verarbeitet die XML-Namen und Namespace für Sie, so dass Sie brauchen nicht zu kümmern. Sie müssen nur durch die ObjectFactory Methoden suchen (und für großes Schema kann es Hunderte von ihnen), das zu finden was Sie brauchen.

Andere Tipps

Dies wird am unteren Rande der Blog-Post bereits erwähnt oben verlinkten, aber das funktioniert wie ein Vergnügen für mich:

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);

Wie angedeutet in einen der oben genannten Antworten, werden Sie nicht ein XMLRootElement auf Ihrem Root-Elemente, wenn in der XSD seine Art als benannte Typ definiert ist, da die genannte Art in Ihrem XSD an anderer Stelle verwendet werden könnte. Versuchen Sie mking es einen anonymen Typ, das heißt statt:

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

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

Sie müßten:

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

@XmlRootElement ist nicht für unmarshalling benötigt -. Wenn man die 2 Parameter Form Unmarshaller # unmarshall verwendet

Also, wenn anstatt das zu tun:

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

sollte man tun:

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

Dieser Code wird nicht @XmlRootElement Anmerkung auf Usertype-Klasse-Ebene erfordern.

Joe Antwort (Joe 26. Juni '09 um 17:26 Uhr) macht es für mich. Die einfache Antwort ist, dass die Abwesenheit einer @XmlRootElement Anmerkung ist kein Problem, wenn Sie einen JAXBElement Marschall. Die Sache, die mich verwirrt ist die erzeugte Object 2 createMyRootElement Methoden hat - die erste keine Parameter und gibt die ausgepackten Gegenstand, nimmt der zweite die ungeöffneten Objekt und gibt es in einem JAXBElement gewickelt und Rangier dass JAXBElement funktioniert gut. Hier ist der Grund-Code, den ich verwendet (ich bin neu in diesem, so entschuldigen, wenn der Code ist nicht korrekt in dieser Antwort formatiert), weitgehend cribbed von link text :

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;
  }
}

Sie können dieses Problem beheben, die Bindung von mit Wie @XmlRootElement Klassen für Basistypen in XSD generieren? .

Hier ist ein Beispiel mit Maven

        <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>

Hier ist der binding.xjb Dateiinhalt

<?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>

Wie Sie wissen, die Antwort ist den Object () zu verwenden. Hier ist ein Beispiel des Codes, der für mich gearbeitet:)

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();
    }

Es funktioniert nicht für uns auch nicht. Aber wir ein weithin zitierten Artikel gefunden haben, dass einige Hintergrund fügt ... Ich werde hier aus Gründen der nächsten Person verknüpfen: http://weblogs.java.net/blog/kohsuke/archive/2006/03/why_does_jaxb_p.html

Bei meiner Erfahrung dieses Problems gibt jemand einen Eureka! Moment .. Ich werde fügen Sie den folgenden:

Ich war auch dieses Problem bekommen, wenn eine XSD-Datei, die ich erzeugt hatte mit IntelliJ des „Gen XSD aus Instanz Dokument“ Menüoption aus.

Wenn ich alle Standardeinstellungen dieses Werkzeugs akzeptiert, erzeugt es eine XSD-Datei, die, wenn sie mit jaxb verwendet, Java-Dateien ohne @XmlRootElement erzeugt. Zur Laufzeit, wenn ich zu Marschall versuchte ich bekam die gleiche Ausnahme wie in dieser Frage diskutiert.

Ich ging zurück zum IntellJ Werkzeug und sah die Standardoption im „Desgin Type“ Drop-Down (was ich natürlich nicht verstehen .. und immer noch nicht, wenn ich ehrlich bin) war:

Desgin Typ:

  

"lokale Elemente / Globale komplexe Typen"

Ich änderte dies

  

"lokale Elemente / Typen"

, jetzt erzeugt er eine (im wesentlichen) verschiedenen XSD, welche die @XmlRootElement erzeugt, wenn sie mit jaxb verwendet. Kann nicht sagen, dass ich die in die und aus der es verstehen, aber es funktionierte für mich.

Mit einem Maven Build können Sie die @XmlRootElement Anmerkung hinzufügen

mit dem "jaxb2-basics-annotate" Plug-in.

Weitere Informationen: siehe

konfigurieren Maven zu generieren Klassen von XML-Schema unter Verwendung von JAXB

und JAXB XJC Codegenerierung

Haben Sie versucht, Ihre XSD wie dies zu ändern?

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

JAXBElement Wrapper arbeitet für Fälle, in denen kein @XmlRootElement von JAXB generiert wird. Diese Hüllen sind in ObjectFactory Klasse von maven-jaxb2-plugin erzeugt. Für zB:

     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;
      }
 }

Nach zwei Tagen sruggling fand ich die Lösung für die problem.You können die Object Klasse für die Klassen zu umgehen, die nicht die hat @XmlRootElement . Object hat Methoden überlastet es um die JAXBElement zu wickeln. Methode: 1 ist die einfache Erstellung des Objekts und Methode: 2 wird das Objekt wickeln mit @JAXBElement . Immer verwenden Methode: 2 , um javax.xml.bind.MarshalException zu vermeiden - mit Ausnahme verknüpft eine @XmlRootElement Anmerkung fehlt

Methode: 1

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

Methode: 2

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

Arbeitscodebeispiel:

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();

Um es soluction sollten Sie eine XML-Konfiguration vor der Bindung mit wsimport zu kompilieren, das Setzen von generateElementProperty als falsch.

     <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>
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top