web-dev-qa-db-fra.com

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

Je suis nouveau dans l'utilisation de JAXB et j'ai utilisé le 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.

Rien ne semble m'empêcher d'instancier directement les éléments, par ex.

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 remplacé si je recompilais à partir d'un schéma modifié.

95
Andrew Coleson

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

Avec des schémas plus compliqués, tels que ceux qui ont des contraintes compliquées sur les valeurs que le contenu d'un élément peut prendre, vous devez parfois créer des objets JAXBElement réels. Ils ne sont généralement pas triviaux à créer à la main, donc le create* les méthodes font le plus dur pour vous. 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 vous obtenez un <style> tag dans 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));

Les trois premières utilisations de ObjectFactory pourraient ê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 écrire un new JAXBElement à la main à chaque fois!

66

Comme l'a souligné @Chris, parfois JAXB ne peut pas fonctionner avec des POJO, car le schéma ne peut pas être mappé exactement sur Java. Dans ces cas, les objets wrapper JAXBElement 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 n'a pas le @XmlRootElement annotation. Par défaut, XJC génère uniquement @XmlRootElement pour certains éléments et pas pour d'autres. La logique exacte est un peu compliquée, mais vous pouvez forcer XJC à générer plus de @XmlRootElement classes utilisant "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 intensif des enveloppes JAXBElement.

Ainsi, dans un modèle d'objet généré par XJC qui fait un usage intensif de JAXBElement (pour une raison quelconque), vous avez besoin d'un moyen de construire ces instances JAXBElement. Le ObjectFactory généré est 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 de le faire.

38
skaffman

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 de nouveaux XYZ (), plus de blocs try/catch. (Je sais, je sais, ... c'est une de ces choses "à quoi pensions-nous!?") ...

9
Bert F