Вопрос по unmarshalling, java, jaxb – когда JAXB unmarshaller.unmarshal возвращает JAXBElement <MySchemaObject> или MySchemaObject?

27

У меня есть два кода в двух разных Java-проектах, выполняющих почти одно и то же (без сортировки ввода веб-сервиса в соответствии с xsd-файлом).

Но в одном случае я должен написать это: (Input является именем заполнителя) (element является вводом OMElement)

<code>ClassLoader clInput = input.ObjectFactory.class.getClassLoader();
JAXBContext jc = JAXBContext.newInstance("input", clInput);
Unmarshaller unmarshaller = jc.createUnmarshaller();
Input input = (Input)unmarshaller.unmarshal( element.getXMLStreamReader() );
</code>

а в другой библиотеке я должен использовать JAXBElement.getValue (), потому что это JAXBElement, который возвращается, и простое приведение (Input) просто завершается сбоем:

<code>Input input = (Input)unmarshaller.unmarshal( element.getXMLStreamReader() ).getValue();
</code>

Вы знаете, что приводит к такой разнице?

Я думаю, что смотреть на XSD имеет смысл, потому что это зависит от того, используете ли вы простой или простой тип. Phani

Ваш Ответ

5   ответов
4

XmlRootElement аннотация на класс вашего корневого элемента.

Если вы генерируете свои классы JAXB из XSD, применяются следующие правила:

if the type of the root element is an anonymous type -> XmlRootElement annotation is added to the generated class if the type of the root element is a top level type -> XmlRootElement annotation is omitted from the generated class

По этой причине я часто выбираю анонимные типы для корневых элементов.

Вы можете настроить имя класса этого анонимного типа с помощью файла настроек. Например. создайте файл bindings.xjc следующим образом:

<jxb:bindings version="1.0"
              xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
              xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <jxb:bindings schemaLocation="yourXsd.xsd" node="/xs:schema">
        <jxb:bindings  node="//xs:element[@name='yourRootElement']">
            <jxb:class name="YourRootElementType"/>
        </jxb:bindings> 
    </jxb:bindings>
</jxb:bindings>
0

JAXBElement<MyObject> вместо желаемогоMyObject.

Я нашел и удалил@XmlElementDecl, Проблема решена.

24

будет возвращен экземпляр этого класса, а если нетJAXBElement будет возвращен.

Если вы хотите, чтобы вы всегда получали экземпляр объекта домена, вы можете использоватьJAXBInstrospector, Ниже приведен пример.

Demo

package forum10243679;

import java.io.StringReader;
import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;

public class Demo {

    private static final String XML = "<root/>";

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Root.class);
        Unmarshaller unmarshaller = jc.createUnmarshaller();
        JAXBIntrospector jaxbIntrospector = jc.createJAXBIntrospector();

        Object object = unmarshaller.unmarshal(new StringReader(XML));
        System.out.println(object.getClass());
        System.out.println(jaxbIntrospector.getValue(object).getClass());

        Object jaxbElement = unmarshaller.unmarshal(new StreamSource(new StringReader(XML)), Root.class);
        System.out.println(jaxbElement.getClass());
        System.out.println(jaxbIntrospector.getValue(jaxbElement).getClass());
    }

}

Output

class forum10243679.Root
class forum10243679.Root
class javax.xml.bind.JAXBElement
class forum10243679.Root
@Saintali - я пытаюсь предоставить пример рабочего кода с каждым из моих ответов. Имя пакета помогает мне найти пример кода, если мне нужно вернуться к нему. Я использовал префиксforum для примеров кода, которые соответствуют общедоступным форумам, таким как переполнение стека (я использую префикс ошибок для воссоздания ошибок), а число соответствует идентификатору вопроса, который можно найти в URL.
Из любопытства, почему вы назвали свою посылку?forum10243679?
1

@XMLRootElement - должно иметь пространство имен:

@XmlRootElement(namespace="http://your.namespace.com/", name="yourRootElement")

Посмотрите на соответствующий вопрос (есть много хороших советов):Исключение класса Cast при попытке демонтировать xml?

Примечание: пространство имен также можно указать с помощью аннотации пакета @ javax.xml.bind.annotation.XmlSchema (обычно в package-info.java).
0

Не позволяя использовать все возможные форматы xsd, я не согласен.

Спасибо всем вашим объяснениям и ссылкам, это код, который я написал для того, чтобы позаботиться об обоих случаях, используя Annotation Introspection. Он работает как для вывода, так и для ввода, и является(in my taste) более общий:

public class JaxbWrapper {

    private static boolean isXmlRootElement(Class classT){

        Annotation[] annotations = classT.getAnnotations();

        for(Annotation annotation : annotations){
            if(annotation instanceof XmlRootElement){
                return true;
            }
        }       

        return false;
    }

    public static Object unmarshall(Class classObjectFactory, Class classObject, XMLStreamReader xmlStreamReader){

        Package pack = classObjectFactory.getPackage();
        String strPackageName = pack.getName();

        Object returnObject = null;

        try {
            JAXBContext jc = JAXBContext.newInstance(strPackageName, classObjectFactory.getClassLoader());

            Unmarshaller unmarshaller = jc.createUnmarshaller();

            returnObject = unmarshaller.unmarshal( xmlStreamReader );

            boolean bIsRootedElement = isXmlRootElement(classObject);
            if(!bIsRootedElement)
            {
                JAXBElement jaxbElement = (JAXBElement) returnObject;
                returnObject = jaxbElement.getValue();              
            }
        }
        catch (JAXBException e) {
            /*...*/
        }   

        return returnObject;
    }

    private static void writeToXml(Class classObjectFactory, Object obj, XMLStreamWriter xmlStreamWriter){

        Package pack = classObjectFactory.getPackage();
        String strPackageName = pack.getName();

        try {       
            JAXBContext jc = JAXBContext.newInstance(strPackageName, classObjectFactory.getClassLoader());
            Marshaller marshaller = jc.createMarshaller();
            marshaller.marshal(obj, xmlStreamWriter);
        }
        catch(JAXBException e) {
            /*...*/
        }       
    }

    public static String marshall(Class classObjectFactory, Class classObject, Object obj){

        Object objectToMarshall = obj; 

        boolean bIsRootedElement = isXmlRootElement(classObject);
        if(!bIsRootedElement)
        {
            Package pack = classObjectFactory.getPackage();
            String strPackageName = pack.getName();

            String strClassName = classObject.getName();

            QName qName = new QName(strPackageName, strClassName);

            JAXBElement jaxbElement = new JAXBElement(qName, classObject, null, obj);

            objectToMarshall = jaxbElement; 
        }

        StringWriter sw = new StringWriter();
        XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newInstance();
        XMLStreamWriter xmlStreamWriter = null;

        try {
            xmlStreamWriter = xmlOutputFactory.createXMLStreamWriter(sw);

            writeToXml(classObjectFactory, objectToMarshall, xmlStreamWriter);

            xmlStreamWriter.flush();
            xmlStreamWriter.close();
        } 
        catch (XMLStreamException e) {
            /*...*/
        }

        return sw.toString();
    }
}
Вы должны быть в состоянии использоватьJAXBIntrospector класс для упрощения вашего кода. Я добавил ответ:stackoverflow.com/a/10253282/383861

Похожие вопросы