2009-06-05 11 views
81

Sono nuovo nell'utilizzo di JAXB e ho utilizzato XJc di JAXB 2.1.3 per generare un insieme di classi dal mio schema XML. Oltre a generare una classe per ogni elemento nel mio schema, ha creato una classe ObjectFactory.Qual è il punto delle classi ObjectFactory di JAXB 2?

Non sembra esserci nulla che mi impedisca di creare istanze di elementi direttamente, ad es.

MyElement element = new MyElement(); 

mentre tutorial sembrano preferire

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

Se guardo in ObjectFactory.java, vedo:

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

quindi qual è il problema? Perché dovrei anche preoccuparmi di mantenere la classe ObjectFactory in giro? Presumo che verrà anche sovrascritto se dovessi ricompilare da uno schema alterato.

risposta

56

compatibilità con le versioni precedenti, non è l'unica ragione. :-P

Con schemi più complicati, come quelli che hanno vincoli complicati sui valori che il contenuto di un elemento può assumere, a volte è necessario creare oggetti reali JAXBElement. Di solito non sono banali da creare a mano, quindi i metodi create* fanno il duro lavoro per te. Esempio (dallo schema XHTML 1.1):

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

questo modo si ottiene un tag <style> in un tag <head>:

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

I primi tre usi della ObjectFactory potrebbero essere considerati superflui (anche se utile per coerenza), ma il quarto rende JAXB molto, molto più facile da usare. Immaginando di dover scrivere un new JAXBElement a mano ogni volta!

+0

Puoi dare un esempio/riferimento di cosa (o di quanto complicato) deve essere un elemento Schema per creare *() per fare qualcosa di utile? Sto riscontrando problemi nel trovare la parte dello schema a cui fai riferimento con il tuo esempio JAXB. Se il mio schema diventa più complicato in seguito, sarebbe certamente bello creare * per gestirne una parte, ma dato che è creato * non si preoccupa nemmeno di creare elementi secondari da solo. –

+0

Se si scarica I tarball XHTML 1.1 e XHTML Modularization 1.1, troverai le directory all'interno chiamate "SCHEMA". Metti tutti i file .xsd nelle stesse directory. Alcuni dei file .xsd importeranno anche http://www.w3.org/2001/xml.xsd; vorrete regolare le posizioni in modo appropriato se non volete che il file venga scaricato ogni volta che eseguite xjc. [cont] –

+0

[cont] La parte specifica di .xsd che specifica il contenuto di un è, in questo caso, in xhtml11-model-1.xsd, sotto il gruppo xhtml.head.content. –

8

compatibilità all'indietro, immagino ...

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

... Niente più ObjectFactory.createXYZ. Il problema con questi metodi di fabbrica era che lanciavano un controllo JAXBException . Ora puoi semplicemente fare nuovo XYZ(), non più blocchi try/catch. (lo so, lo so ... questo è uno dei quelle "che cosa stavamo pensando !?" cose) ...

34

Come ha sottolineato @Chris, a volte JAXB non può funzionare con POJO, perché lo schema non può essere mappato esattamente su Java. In questi casi, gli oggetti wrapper JAXBElement sono necessari per fornire le informazioni sul tipo aggiuntivo.

Ci sono due esempi concreti che ho riscontrato dove è comune.

  • Se si desidera marshalling di un oggetto di una classe che non ha la @XmlRootElement annotazione. Di default XJC genera solo @XmlRootElement per alcuni elementi e non per altri.La logica esatta per questo è un po 'complicata, ma puoi forzare XJC a generare più classi @XmlRootElement utilizzando "simple binding mode"

  • Quando lo schema utilizza gruppi di sostituzioni. Questo è un uso piuttosto avanzato dello schema, ma XJC traduce i gruppi di sostituzione in Java facendo un uso pesante dei wrapper JAXBElement.

Quindi, in un modello a oggetti XJC generati che fa un uso pesante di JAXBElement (per qualsiasi motivo), è necessario un modo di costruire quei JAXBElement istanze. Lo ObjectFactory generato è di gran lunga il modo più semplice per farlo. È possibile costruirli da soli, ma è goffo e soggetto a errori.

+0

Grazie per gli esempi aggiuntivi! –

+2

Wow, questa è una risposta vincente. +1 –

+2

Anche 3 mesi di ritardo :) – skaffman