Was ist der Sinn der ObjectFactory-Klassen von JAXB 2?

97

Ich bin neu in der Verwendung von JAXB und habe xjc von JAXB 2.1.3 verwendet, um eine Reihe von Klassen aus meinem XML-Schema zu generieren. Zusätzlich zum Generieren einer Klasse für jedes Element in meinem Schema wurde eine ObjectFactory-Klasse erstellt.

Es scheint mich nichts daran zu hindern, die Elemente direkt zu instanziieren, z

MyElement element = new MyElement();

während Tutorials zu bevorzugen scheinen

MyElement element = new ObjectFactory().createMyElement();

Wenn ich in ObjectFactory.java schaue, sehe ich:

public MyElement createMyElement() {
    return new MyElement();
}

Also, was ist der Deal? Warum sollte ich mir überhaupt die Mühe machen, die ObjectFactory-Klasse beizubehalten? Ich gehe davon aus, dass es auch überschrieben wird, wenn ich aus einem geänderten Schema neu kompiliere.

Andrew Coleson
quelle
Ich bin nicht sicher, ob es sich um ein beabsichtigtes Design handelt, aber ich habe festgestellt, dass ObjectFactory eine ideale Klasse für die Erstellung von JAXBContext ist. Sie müssen dort einige Klassen aufzählen, und JAXB folgt ihren Methoden usw., sodass sie so etwas wie Roots sind. Und ObjectFactory hat Verweise auf alle Elemente, sodass es ausreicht, nur ObjectFactory.class zu verwenden, um JAXBContext mit allen relevanten Klassen zu erstellen.
Vbezhenar

Antworten:

67

Abwärtskompatibilität ist nicht der einzige Grund. :-P

Bei komplizierteren Schemata, z. B. solchen, bei denen die Werte, die der Inhalt eines Elements annehmen kann, komplizierte Einschränkungen aufweisen, müssen Sie manchmal tatsächliche JAXBElementObjekte erstellen . Sie sind normalerweise nicht trivial von Hand zu erstellen, daher create*erledigen die Methoden die harte Arbeit für Sie. Beispiel (aus dem XHTML 1.1-Schema):

@XmlElementDecl(namespace = "http://www.w3.org/1999/xhtml", name = "style", scope = XhtmlHeadType.class)
public JAXBElement<XhtmlStyleType> createXhtmlHeadTypeStyle(XhtmlStyleType value) {
    return new JAXBElement<XhtmlStyleType>(_XhtmlHeadTypeStyle_QNAME, XhtmlStyleType.class, XhtmlHeadType.class, value);
}

So erhalten Sie ein <style>Tag in ein <head>Tag:

ObjectFactory factory = new ObjectFactory();
XhtmlHtmlType html = factory.createXhtmlHtmlType();
XhtmlHeadType head = factory.createXhtmlHeadType();
html.setHead(head);
XhtmlStyleType style = factory.createXhtmlStyleType();
head.getContent().add(factory.createXhtmlHeadTypeStyle(style));

Die ersten drei Verwendungen von ObjectFactorykönnten als überflüssig angesehen werden (obwohl sie für die Konsistenz nützlich sind), aber die vierte macht die Verwendung von JAXB sehr viel einfacher. Imaging muss new JAXBElementjedes Mal von Hand ausschreiben!

Chris Jester-Young
quelle
Können Sie ein Beispiel / eine Referenz dafür geben, was (oder wie kompliziert) ein Schemaelement sein muss, damit create * () etwas Nützliches tut? Ich habe Probleme, den Teil des Schemas zu finden, auf den Sie mit Ihrem JAXB-Beispiel verweisen. Wenn mein Schema später komplizierter wird, wäre es sicherlich schön, wenn create * einen Teil davon für mich handhaben würde, aber da es create * ist, macht es sich nicht einmal die Mühe,
Unterelemente
Wenn Sie die Tarballs XHTML 1.1 und XHTML Modularization 1.1 herunterladen, finden Sie darin Verzeichnisse mit dem Namen "SCHEMA". Legen Sie alle .xsd-Dateien in denselben Verzeichnissen ab. Einige der .xsd-Dateien importieren auch w3.org/2001/xml.xsd . Sie sollten die Speicherorte entsprechend anpassen, wenn Sie nicht möchten, dass die Datei jedes Mal heruntergeladen wird, wenn Sie xjc ausführen. [Fortsetzung]
Chris Jester-Young
[cont] Der spezifische Teil der .xsd, der den Inhalt eines <head> angibt, befindet sich in diesem Fall in xhtml11-model-1.xsd unter der Gruppe xhtml.head.content.
Chris Jester-Young
2
Auf jeden Fall richtet niemand eine Waffe auf Ihren Kopf und sagt, dass Sie ObjectFactory verwenden müssen (obwohl ich es praktisch finde), aber wenn Sie auf einen Fall stoßen, in dem es wirklich nützlich ist, werden Sie es wissen. :-)
Chris Jester-Young
Vielen Dank! Ich denke, mein Schema ist einfach nicht kompliziert genug, aber ich werde es für die Zukunft im Auge behalten. :) Ich wusste, dass ich etwas vermissen musste.
Andrew Coleson
39

Wie @Chris betonte, kann JAXB manchmal nicht mit POJOs arbeiten, da das Schema nicht genau auf Java abgebildet werden kann. In diesen Fällen sind JAXBElementWrapper-Objekte erforderlich, um die zusätzlichen Typinformationen bereitzustellen.

Es gibt zwei konkrete Beispiele, auf die ich gestoßen bin, wo dies üblich ist.

  • Wenn Sie ein Objekt einer Klasse ohne @XmlRootElementAnnotation marshallen möchten . Standardmäßig generiert XJC nur @XmlRootElementfür einige Elemente und nicht für andere. Die genaue Logik hierfür ist etwas kompliziert, aber Sie können XJC zwingen, @XmlRootElementmithilfe des "einfachen Bindungsmodus" mehr Klassen zu generieren.

  • Wenn Ihr Schema Substitutionsgruppen verwendet. Dies ist eine ziemlich fortgeschrittene Schema-Verwendung, aber XJC übersetzt Substitutionsgruppen in Java, indem es JAXBElementWrapper stark nutzt .

In einem von XJC generierten Objektmodell, das JAXBElement(aus welchen Gründen auch immer) stark genutzt wird, benötigen Sie eine Möglichkeit, diese JAXBElementInstanzen zu erstellen . Das Generierte ObjectFactoryist bei weitem der einfachste Weg, dies zu tun. Sie können sie selbst erstellen, dies ist jedoch umständlich und fehleranfällig.

Skaffman
quelle
Danke für die zusätzlichen Beispiele!
Andrew Coleson
2
Wow, das ist eine gewinnende Antwort. +1
Chris Jester-Young
Ich verwende Annox gerne, um das XmlRootElement in 95% der Fälle zu generieren. Wenn ich ein Element habe, das sich auf einen komplexen Typ bezieht, möchte ich XmlRootElement (also eher 100%, da ich den Anwendungsfall nicht getroffen habe, in dem ich das nicht möchte noch)
Dean Hiller
9

Abwärtskompatibilität, denke ich ...

http://weblogs.java.net/blog/kohsuke/archive/2005/08/a_story_of_migr.html :

... nicht mehr ObjectFactory.createXYZ. Das Problem mit diesen Factory-Methoden war, dass sie eine überprüfte JAXBException auslösen. Jetzt können Sie einfach neue XYZ () erstellen, keine Try / Catch-Blöcke mehr. (Ich weiß, ich weiß, ... das ist eines dieser "Was haben wir uns gedacht?" - Dinge) ...

Bert F.
quelle