Qual è il punto delle classi ObjectFactory di JAXB 2?


98

Sono nuovo nell'uso di JAXB e ho usato xjc di JAXB 2.1.3 per generare un set di classi dal mio XML Schema. Oltre a generare una classe per ogni elemento nel mio schema, ha creato una classe ObjectFactory.

Non sembra esserci nulla che mi impedisca di istanziare direttamente gli elementi, ad es

MyElement element = new MyElement();

mentre i 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 modificato.


Non sono sicuro che sia design inteso, ma ho trovato ObjectFactory una classe ideale da utilizzare per la creazione di JAXBContext. Devi enumerare alcune classi lì e JAXB seguirà i loro metodi, ecc., Quindi sono qualcosa come root. E ObjectFactory ha riferimenti a tutti gli elementi, quindi è sufficiente utilizzare ObjectFactory.class per creare JAXBContext con tutte le classi rilevanti.
vbezhenar

Risposte:


68

La 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 JAXBElementoggetti reali . Di solito non sono banali da creare a mano, quindi i create*metodi 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);
}

Ecco come inserire un <style>tag in un <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));

I primi tre utilizzi di ObjectFactorypotrebbero essere considerati superflui (sebbene utili per coerenza), ma il quarto rende JAXB molto, molto più facile da usare. Immaginare di dover scrivere a new JAXBElementmano ogni volta!


Potete fornire un esempio / riferimento di cosa (o quanto complicato) deve essere un elemento dello schema affinché create * () possa fare qualcosa di utile? Ho problemi a trovare la parte dello schema a cui fai riferimento con il tuo esempio JAXB. Se il mio schema diventa più complicato in seguito, sarebbe sicuramente bello che create * gestisse una parte di esso per me, ma poiché è create * non si preoccupa nemmeno di creare sottoelementi da solo ..
Andrew Coleson

Se scarichi i tarball XHTML 1.1 e XHTML Modularization 1.1, troverai delle directory all'interno chiamate "SCHEMA". Metti tutti i file .xsd nelle stesse directory. Alcuni dei file .xsd importeranno anche w3.org/2001/xml.xsd ; ti consigliamo di regolare le posizioni in modo appropriato se non vuoi che il file venga scaricato ogni volta che esegui xjc. [cont]
Chris Jester-Young,

[cont] La parte specifica del .xsd che specifica il contenuto di un <head> è, in questo caso, in xhtml11-model-1.xsd, sotto il gruppo xhtml.head.content.
Chris Jester-Young,

2
In ogni caso, nessuno ti punta una pistola alla testa dicendo che devi usare ObjectFactory (anche se lo trovo comodo da usare), ma quando ti imbatti in un caso in cui è veramente utile, lo saprai. :-)
Chris Jester-Young,

Grazie! Immagino che il mio schema non sia abbastanza complicato, ma lo terrò a mente per il futuro. :) Sapevo che dovevo perdere qualcosa.
Andrew Coleson

39

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 JAXBElementoggetti wrapper sono necessari per fornire le informazioni aggiuntive sul tipo.

Ci sono due esempi concreti in cui mi sono imbattuto in cui questo è comune.

  • Se vuoi effettuare il marshalling di un oggetto di una classe che non ha l' @XmlRootElementannotazione. Per impostazione predefinita, XJC genera solo @XmlRootElementper alcuni elementi e non per altri. La logica esatta per questo è un po 'complicata, ma puoi forzare XJC a generare più @XmlRootElementclassi usando la "modalità di associazione semplice"

  • Quando il tuo schema utilizza i gruppi di sostituzione. Questo è un utilizzo dello schema piuttosto avanzato, ma XJC traduce i gruppi di sostituzione in Java facendo un uso massiccio di JAXBElementwrapper.

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


Grazie per gli esempi aggiuntivi!
Andrew Coleson

2
Wow, questa è una risposta vincente. +1
Chris Jester-Young,

Mi piace usare annox per generare XmlRootElement il 95% delle volte se ho un elememtn che si riferisce a un complexType, voglio XmlRootElement (beh, più simile al 100% perché non ho colpito il caso d'uso in cui non lo voglio ancora)
Dean Hiller

9

Compatibilità con le versioni precedenti, immagino ...

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

... Non più ObjectFactory.createXYZ. Il problema con quei metodi di fabbrica era che lanciano un'eccezione JAXBException controllata. Ora puoi semplicemente fare new XYZ (), non più blocchi try / catch. (Lo so, lo so, ... questa è una di quelle cose "a cosa stavamo pensando !?") ...

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.