Варианты JAXBContext.newInstance

Я экспериментирую с различными формами метода newInstance в классе JAXBContext (я использую реализацию Sun JAXB по умолчанию, которая поставляется с Oracle JDK 1.7).

Мне не ясно, когда это просто передать методу newInstance конкретные классы по сравнению с классом ObjectFactory. Я должен отметить, что я использую JAXB исключительно для разбора XML файлов, т.е. Только в направлении XML- > Java.

Здесь абсолютно минимальный код, демонстрирующий мою точку зрения:

xsd file

<?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>

Учитывая вышеупомянутый XSD, следующие вызовы JAXBInstance.newInstance преуспевают в создании контекста, который может анализировать образец a.xml:

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

Однако при прохождении example.a.RootType.class не удается выполнить javax.xml.bind.UnmarshalException во время выполнения:

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

Может ли кто-нибудь пролить свет? Причина, по которой я экспериментирую в этих вариантах JAXBContext:: newInstance, заключается в том, что я наткнулся на эту проблему, где принятый ответ включал в себя возможность "создание контекста JAXB, основанного на отдельных классах, а не на объектных фабриках". Пример a.xml и код JAXB Java, который я использую, следует в конце сообщения.

используется пример a.xml

<?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>

код анализа 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() );
}

Ответы

Ответ 1

Модель JAXB, созданная с помощью XML-схемы

При создании JAXBContext из модели, сгенерированной из XML-схемы, я всегда рекомендую сделать это в имени пакета сгенерированных классов.

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

Еще лучше использовать метод newInstance, который принимает параметр ClassLoader. Это избавит вас от горя, когда вы перейдете от среды Java SE к среде Java EE.

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

Когда вы создаете JAXBContext в имени пакета, JAXB impl предполагает, что вы сгенерировали модель из схемы XML и вытягиваете класс ObjectFactory, поскольку он всегда генерирует класс, аннотированный с помощью @XmlRegistry с этим именем.

Начиная с модели Java

Это когда я рекомендую людям использовать методы newInstance, которые принимают классы. При начальной загрузке JAXBContext из классов JAXB нет ничего особенного в классе под названием ObjectFactory. Роль ObjectFactory может быть воспроизведена любым классом, аннотированным с помощью @XmlRegistry, поэтому он не будет автоматически искать. Вот почему ваш прецедент работал, когда вы явно ссылались на ObjectFactory и не сработали, когда вы этого не сделали.