Quel est l'intérêt des classes ObjectFactory de JAXB 2?

98

Je suis nouveau dans l'utilisation de JAXB et j'ai utilisé xjc de JAXB 2.1.3 pour générer un ensemble de classes à partir de mon schéma XML. En plus de générer une classe pour chaque élément de mon schéma, il a créé une classe ObjectFactory.

Il ne semble y avoir rien qui m'empêche d'instancier directement les éléments, par exemple

MyElement element = new MyElement();

alors que les tutoriels semblent préférer

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

Si je regarde ObjectFactory.java, je vois:

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

alors quel est le problème? Pourquoi devrais-je même prendre la peine de conserver la classe ObjectFactory? Je suppose qu'il sera également écrasé si je devais recompiler à partir d'un schéma modifié.

Andrew Coleson
la source
Je ne sais pas si c'est la conception prévue, mais j'ai trouvé ObjectFactory une classe idéale à utiliser pour la création de JAXBContext. Vous devez y énumérer certaines classes et JAXB suivra leurs méthodes, etc., donc elles ressemblent à des racines. Et ObjectFactory a des références à tous les éléments, il suffit donc d'utiliser ObjectFactory.class pour créer JAXBContext avec toutes les classes pertinentes.
vbezhenar

Réponses:

68

La rétrocompatibilité n'est pas la seule raison. :-P

Avec des schémas plus compliqués, tels que ceux qui ont des contraintes complexes sur les valeurs que le contenu d'un élément peut prendre, vous devez parfois créer des JAXBElementobjets réels . Ils ne sont généralement pas triviaux à créer à la main, les create*méthodes font donc le travail à votre place. Exemple (du schéma 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);
}

Voici comment insérer une <style>balise dans une <head>balise:

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

Les trois premières utilisations du ObjectFactorypeuvent être considérées comme superflues (bien qu'utiles pour la cohérence), mais la quatrième rend JAXB beaucoup, beaucoup plus facile à utiliser. Imagerie devant à new JAXBElementchaque fois écrire un à la main!

Chris Jester-Young
la source
Pouvez-vous donner un exemple / une référence de ce que (ou de la complexité) d'un élément de schéma doit être pour que create * () fasse quelque chose d'utile? J'ai du mal à trouver la partie du schéma que vous référencez avec votre exemple JAXB. Si mon schéma se complique plus tard, ce serait certainement bien pour create * d'en gérer une partie pour moi, mais comme il est create *, cela ne prend même pas la peine de créer des sous-éléments tout seul.
Andrew Coleson
Si vous téléchargez les archives tar XHTML 1.1 et XHTML Modularization 1.1, vous trouverez à l'intérieur des répertoires appelés "SCHEMA". Placez tous les fichiers .xsd dans les mêmes répertoires. Certains fichiers .xsd importeront également w3.org/2001/xml.xsd ; vous voudrez ajuster les emplacements de manière appropriée si vous ne voulez pas que le fichier soit téléchargé chaque fois que vous exécutez xjc. [cont]
Chris Jester-Young
[cont] La partie spécifique du .xsd qui spécifie le contenu d'un <head> est, dans ce cas, dans xhtml11-model-1.xsd, sous le groupe xhtml.head.content.
Chris Jester-Young
2
Dans tous les cas, personne ne pointe un pistolet sur votre tête en disant que vous devez utiliser ObjectFactory (même si je le trouve pratique à utiliser), mais lorsque vous rencontrez un cas où c'est vraiment utile, vous le saurez. :-)
Chris Jester-Young
Merci! Je suppose que mon schéma n'est tout simplement pas assez compliqué, mais je le garderai à l'esprit pour le futur. :) Je savais que je devais manquer quelque chose.
Andrew Coleson le
39

Comme @Chris l'a souligné, parfois JAXB ne peut pas fonctionner avec les POJO, car le schéma ne peut pas être mappé exactement sur Java. Dans ces cas, les JAXBElementobjets wrapper sont nécessaires pour fournir les informations de type supplémentaires.

Il y a deux exemples concrets que j'ai rencontrés où cela est courant.

  • Si vous souhaitez marshaler un objet d'une classe qui ne possède pas l' @XmlRootElementannotation. Par défaut, XJC ne génère que @XmlRootElementpour certains éléments et pas pour d'autres. La logique exacte pour cela est un peu compliquée, mais vous pouvez forcer XJC à générer plus de @XmlRootElementclasses en utilisant le "mode de liaison simple"

  • Lorsque votre schéma utilise des groupes de substitution. Il s'agit d'une utilisation de schéma assez avancée, mais XJC traduit les groupes de substitution en Java en faisant un usage JAXBElementintensif des wrappers.

Donc, dans un modèle d'objet généré par XJC qui en fait un usage intensif JAXBElement(pour une raison quelconque), vous avez besoin d'un moyen de construire ces JAXBElementinstances. Le généré ObjectFactoryest de loin le moyen le plus simple de le faire. Vous pouvez les construire vous-même, mais c'est maladroit et sujet aux erreurs.

skaffman
la source
Merci pour les exemples supplémentaires!
Andrew Coleson le
2
Wow, c'est une réponse gagnante. +1
Chris Jester-Young
J'aime utiliser annox pour générer le XmlRootElement 95% du temps si j'ai un élément qui fait référence à un complexType, je veux XmlRootElement (enfin, plus comme 100% car je n'ai pas atteint le cas d'utilisation où je ne veux pas que encore)
Dean Hiller
9

Rétrocompatibilité, je suppose ...

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

... Plus d'ObjectFactory.createXYZ. Le problème avec ces méthodes d'usine était qu'elles lançaient une exception JAXBException vérifiée. Maintenant, vous pouvez simplement faire un nouveau XYZ (), plus de blocs try / catch. (Je sais, je sais, ... c'est une de ces choses "à quoi pensions-nous!?") ...

Bert F
la source