web-dev-qa-db-fra.com

Variations de JAXBContext.newInstance

J'expérimente les différentes formes de la méthode newInstance dans la classe JAXBContext (J'utilise l'implémentation Sun JAXB par défaut fournie avec Oracle JDK 1.7).

Ce n'est pas clair pour moi quand il est juste de passer à la méthode newInstance les classes concrètes par rapport à la classe ObjectFactory. Je dois noter que j'utilise JAXB uniquement pour l'analyse de fichiers XML, c'est-à-dire uniquement dans le sens XML-> Java.

Voici le code absolument minimal qui démontre mon point:

fichier xsd

<?xml version="1.0" encoding="UTF-8"?>
<schema elementFormDefault="qualified"
    xmlns          ="http://www.w3.org/2001/XMLSchema"
    xmlns:a        ="http://www.example.org/A"
    targetNamespace="http://www.example.org/A">
    <element name="root" type="a:RootType"></element>

    <complexType name="RootType">
       <sequence>
           <element name="value" type="string"></element>
       </sequence>
    </complexType>
</schema>

Étant donné le XSD ci-dessus, les invocations JAXBInstance.newInstance réussissent à créer un contexte qui peut analyser un exemple a.xml de fichier:

  • jc = JAXBContext.newInstance ("example.a");
  • jc = JAXBContext.newInstance (exemple.a.ObjectFactory.class);
  • jc = JAXBContext.newInstance (exemple.a.RootType.class, exemple.a.ObjectFactory.class);

Cependant, le passage de example.a.RootType.class seul échoue avec javax.xml.bind.UnmarshalException lors de l'exécution:

jc = JAXBContext.newInstance(example.a.RootType.class); // this fails at runtime.

Quelqu'un peut-il nous éclairer? La raison pour laquelle j'expérimente sur ces variations JAXBContext :: newInstance est que je suis tombé sur ce problème où la réponse acceptée incluait l'option "construire le contexte JAXB basé sur des classes individuelles plutôt que sur des usines d'objets ". L'exemple a.xml et le [~ # ~] jaxb [~ ​​# ~] Java code que j'utilise suivre à la fin du post.

exemple a.xml utilisé

<?xml version="1.0" encoding="UTF-8"?>
<a:root xmlns:a="http://www.example.org/A"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.example.org/A A.xsd">
    <a:value>foo</a:value>
</a:root>

Code d'analyse JAXB

public static void main (String args[]) throws JAXBException, FileNotFoundException {
    JAXBContext jc = null;
    message("using package context (press any key:)");
    jc = JAXBContext.newInstance("example.a");
    work(jc); // SUCCEEDS

    message("using Object factory (press any key):");
    jc = JAXBContext.newInstance(example.a.ObjectFactory.class);
    work(jc); // SUCCEEDS

    message("using class enumeration (press any key):");
    try {
        jc = JAXBContext.newInstance(example.a.RootType.class);
        work(jc);  // FAILS
    } catch (javax.xml.bind.UnmarshalException e) {
        e.printStackTrace();
    }

    message("using class enumeration and Object factory too (press any key):");
    jc = JAXBContext.newInstance(example.a.RootType.class, example.a.ObjectFactory.class);
    work(jc); // SUCCEEDS

}

private static void work(JAXBContext jc) throws JAXBException, FileNotFoundException {
    Unmarshaller u = jc.createUnmarshaller();
    RootType root = ((JAXBElement<RootType>)u.unmarshal( new FileInputStream( "a.xml" ))).getValue();
    System.out.println( root.getValue() );
}
19

modèle JAXB généré à partir d'un schéma XML

Lors de la création d'un JAXBContext à partir d'un modèle généré à partir d'un schéma XML, je recommande toujours de le faire sur le nom du package des classes générées.

JAXBContext jc = JAXBContext.newInstance("example.a");

Il est encore préférable d'utiliser une méthode newInstance qui prend un paramètre ClassLoader. Cela vous évitera du chagrin lorsque vous passerez d'un environnement Java SE à Java EE).

JAXBContext jc = JAXBContext.newInstance("example.a", example.a.ObjectFactory.class.getClassLoader());

Lorsque vous créez le JAXBContext sur le nom du package, l'impl JAXB suppose que vous avez généré le modèle à partir d'un schéma XML et extrait la classe ObjectFactory car il génère toujours la classe annotée avec @XmlRegistry avec ce nom.

à partir d'un Java

C'est à ce moment que je recommande aux gens d'utiliser les méthodes newInstance qui prennent des cours. Lors du démarrage d'un JAXBContext à partir de classes JAXB, il n'y a rien de spécial à propos d'une classe appelée ObjectFactory. Le rôle de ObjectFactory peut être joué par n'importe quelle classe annotée avec @XmlRegistry donc il n'est pas automatiquement recherché. C'est pourquoi votre cas d'utilisation a fonctionné lorsque vous référencez explicitement ObjectFactory et a échoué lorsque vous ne l'avez pas fait.

16
bdoughan