Um zusammenzufassen, was andere bereits gesagt oder angedeutet haben, sind die Regeln, nach denen JAXB XJC entscheidet, ob die @XmlRootElement
Annotation einer generierten Klasse hinzugefügt werden soll oder nicht, nicht trivial ( siehe diesen Artikel ).
@XmlRootElement
existiert, weil die JAXB-Laufzeit bestimmte Informationen benötigt, um ein bestimmtes Objekt zu marshallen / unmarshalen, insbesondere den Namen und den Namespace des XML-Elements. Sie können nicht einfach ein altes Objekt an den Marshaller übergeben. @XmlRootElement
bietet diese Informationen.
Die Anmerkung ist jedoch nur eine Annehmlichkeit - JAXB benötigt sie nicht. Die Alternative dazu besteht darin, JAXBElement
Wrapper-Objekte zu verwenden, die dieselben Informationen wie @XmlRootElement
, jedoch in Form eines Objekts, anstelle einer Anmerkung bereitstellen .
Das JAXBElement
Erstellen von Objekten ist jedoch umständlich, da Sie den Namen und den Namespace des XML-Elements kennen müssen, was in der Geschäftslogik normalerweise nicht der Fall ist.
Zum Glück generiert XJC beim Generieren eines Klassenmodells auch eine Klasse namens ObjectFactory
. Dies dient zum Teil der Abwärtskompatibilität mit JAXB v1, ist aber auch ein Ort, an dem XJC generierte Factory-Methoden platzieren kann, mit denen JAXBElement
Wrapper um Ihre eigenen Objekte erstellt werden. Es behandelt den XML-Namen und den Namespace für Sie, sodass Sie sich darüber keine Gedanken machen müssen. Sie müssen nur die ObjectFactory
Methoden durchsehen (und für große Schemata können es Hunderte sein), um die gewünschte zu finden.
new ObjectFactory().createPositionReport(positionReport)
kehrt zurückJAXBElement<PositionReport>
JXBElement
? In meinem Fall ist die Factory-Methode 0-arity und gibt nur einnew
Objekt zurück. (Warum erhalten einige Klassen JAXBElement-Wrapper-Helfer und andere nicht?) In diesem Fall müssen wir den Wrapper wohl selbst erstellen?Dies wird am Ende des bereits oben verlinkten Blog-Beitrags erwähnt, aber das funktioniert für mich wie ein Vergnügen:
quelle
jc
in dem obigen Ausschnitt?Wie in einer der obigen Antworten angedeutet, erhalten Sie kein XMLRootElement für Ihr Stammelement, wenn der Typ in der XSD als benannter Typ definiert ist, da dieser benannte Typ an anderer Stelle in Ihrer XSD verwendet werden könnte. Versuchen Sie es mit einem anonymen Typ, dh anstelle von:
du würdest haben:
quelle
@XmlRootElement wird für das Unmarshalling nicht benötigt - wenn man die 2-Parameter-Form von Unmarshaller # unmarshall verwendet.
Also, wenn anstatt zu tun:
man sollte tun:
Für den letzteren Code ist keine Annotation @XmlRootElement auf UserType-Klassenebene erforderlich.
quelle
String pathname = "file.xml"; InputStream stream = new FileInputStream(pathname); JAXBContext jaxbContext = JAXBContext.newInstance(UserType.class); Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller(); XMLInputFactory factory = XMLInputFactory.newInstance(); XMLEventReader someSource = factory.createXMLEventReader(stream); JAXBElement<UserType> userElement = jaxbUnmarshaller.unmarshal(someSource, UserType.class); UserType user = userElement.getValue();
Joes Antwort (Joe 26. Juni 09 um 17:26) macht es für mich. Die einfache Antwort lautet, dass das Fehlen einer @ XMLRootElement-Annotation kein Problem darstellt, wenn Sie ein JAXBElement marshallen. Was mich verwirrt hat, ist, dass die generierte ObjectFactory über zwei createMyRootElement-Methoden verfügt - die erste verwendet keine Parameter und gibt das nicht umschlossene Objekt an, die zweite nimmt das nicht umhüllte Objekt und gibt es in ein JAXBElement verpackt zurück, und das Marshalling, dass JAXBElement einwandfrei funktioniert. Hier ist der grundlegende Code, den ich verwendet habe (ich bin neu in diesem Bereich, also entschuldige mich, wenn der Code in dieser Antwort nicht richtig formatiert ist), der größtenteils aus dem Linktext stammt :
quelle
Sie können dieses Problem mithilfe der Bindung unter Generieren von @ XMLRootElement-Klassen für Basistypen in XSD beheben . .
Hier ist ein Beispiel mit Maven
Hier ist der
binding.xjb
Dateiinhaltquelle
Wie Sie wissen, besteht die Antwort darin, die ObjectFactory () zu verwenden. Hier ist ein Beispiel des Codes, der für mich funktioniert hat :)
quelle
Es funktioniert auch nicht für uns. Aber wir haben einen vielzitierten Artikel gefunden, der EINIGEN Hintergrund hinzufügt ... Ich werde hier für die nächste Person darauf verlinken: http://weblogs.java.net/blog/kohsuke/archive/2006/03 /why_does_jaxb_p.html
quelle
Nachdem ich zwei Tage lang gekämpft hatte, fand ich die Lösung für das Problem. Sie können die ObjectFactory- Klasse verwenden, um die Klassen zu umgehen, die nicht über @XmlRootElement verfügen . ObjectFactory hat Methoden überladen, um es um das JAXBElement zu wickeln.
Methode 1 das Objekt einfach.
Methode: 2 umschließt das Objekt mit @JAXBElement .
Verwenden Sie immer Methode: 2 , um javax.xml.bind.MarshalException zu vermeiden - bei verknüpfter Ausnahme fehlt eine @ XMLRootElement-Annotation.
Den Beispielcode finden Sie unten
Methode: 1 erstellt das Objekt einfach
Methode: 2 umschließt das Objekt mit @JAXBElement .
Arbeitscodebeispiel:
quelle
Falls meine Erfahrung mit diesem Problem jemandem eine Eureka gibt! Moment .. Ich werde folgendes hinzufügen:
Dieses Problem trat auch auf, wenn ich eine xsd-Datei verwendete, die ich mit der Menüoption "xsd aus Instanzdokument generieren" von IntelliJ generiert hatte.
Als ich alle Standardeinstellungen dieses Tools akzeptierte, wurde eine xsd-Datei generiert, die bei Verwendung mit jaxb Java-Dateien mit der Nr
@XmlRootElement
. 1 generierte . Zur Laufzeit, als ich versuchte zu marshallen, bekam ich die gleiche Ausnahme wie in dieser Frage beschrieben.Ich kehrte zum IntellJ-Tool zurück und sah die Standardoption in der Dropdown-Liste "Desgin Type" (die ich natürlich nicht verstanden habe ... und immer noch nicht, wenn ich ehrlich bin):
Desgin-Typ:
Ich habe das geändert in
Jetzt wurde ein (wesentlich) anderes xsd generiert, das
@XmlRootElement
bei Verwendung mit jaxb das erzeugte. Ich kann nicht sagen, dass ich die Vor- und Nachteile verstehe, aber es hat bei mir funktioniert.quelle
Mit einem Maven-Build können Sie die
@XmlRootElement
Anmerkung hinzufügenmit dem "
jaxb2-basics-annotate
Plugin ".Weitere Informationen: siehe
Konfigurieren Sie Maven so, dass mit JAXB Klassen aus dem XML-Schema generiert werden
und JAXB XJC-Codegenerierung
quelle
JAXBElement-Wrapper funktionieren in Fällen, in denen
@XmlRootElement
von JAXB no generiert wird. Diese Wrapper sind inObjectFactory
Klassen verfügbar , die von generiert wurdenmaven-jaxb2-plugin
. Zum Beispiel:quelle
Haben Sie versucht, Ihre xsd so zu ändern?
quelle
Um dies zu beheben, sollten Sie vor dem Kompilieren mit wsimport eine XML-Bindung konfigurieren und generateElementProperty auf false setzen.
quelle
<jaxb:bindings> ... <jaxws:bindings> ... </jaxws:bindings> ... </jaxb:bindings>
Das Thema ist ziemlich alt, aber im geschäftlichen Kontext von Unternehmen immer noch relevant. Ich habe versucht zu vermeiden, die xsds zu berühren, um sie in Zukunft einfach zu aktualisieren. Hier sind meine Lösungen ..
1. Meistens
xjc:simple
ist ausreichendEs werden hauptsächlich XmlRootElements zum Importieren von xsd-Definitionen erstellt.
2. Teilen Sie Ihre
jaxb2-maven-plugin
HinrichtungenIch habe festgestellt, dass es einen großen Unterschied macht, wenn Sie versuchen, Klassen aus mehreren xsd-Definitionen anstelle einer Ausführungsdefinition pro xsd zu generieren.
Wenn Sie also eine Definition mit mehreren haben
<source>
, versuchen Sie einfach, diese zu teilen:Der Generator erkennt nicht, dass möglicherweise eine Klasse ausreicht, und erstellt daher pro Ausführung benutzerdefinierte Klassen. Und genau das brauche ich;).
quelle