什么时候JAXB unmarshaller.unmarshal返回JAXBElement <myschemaobject>或MySchemaObject?</myschemaobject>

时间:2012-04-20 09:36:18

标签: java jaxb unmarshalling

我有两个代码,在两个不同的java项目中,做了几乎相同的事情,(根据xsd文件解组web服务的输入)。

但在一种情况下我应该这样写:(输入是一个占位符名称)(元素是OMElement输入)

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

在另一个lib中我必须使用JAXBElement.getValue(),因为它是一个返回的JAXBElement,而一个简单的(Input)转换只是崩溃:

Input input = (Input)unmarshaller.unmarshal( element.getXMLStreamReader() ).getValue();

你知道是什么导致了这种差异吗?

5 个答案:

答案 0 :(得分:24)

如果根元素唯一对应于Java类,则将返回该类的实例,如果不是,则返回JAXBElement

如果您想确保始终获得域对象的实例,则可以使用JAXBInstrospector。以下是一个例子。

<强>演示

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

}

<强>输出

class forum10243679.Root
class forum10243679.Root
class javax.xml.bind.JAXBElement
class forum10243679.Root

答案 1 :(得分:4)

这取决于你的根元素类的XmlRootElement annotation的存在。

如果从XSD生成JAXB类,则应用以下规则:

  • 如果根元素的类型是匿名类型 - &gt; XmlRootElement注释将添加到生成的类
  • 如果根元素的类型是顶级类型 - &gt;生成的类
  • 中省略了XmlRootElement注释

出于这个原因,我经常为根元素选择匿名类型。

您可以使用自定义文件自定义此匿名类型的类名。例如。像这样创建一个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>

答案 2 :(得分:1)

您需要添加到JAXB生成的类@XMLRootElement - 它应该具有命名空间:

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

查看相关问题(有很多好的提示):Class Cast Exception when trying to unmarshall xml?

答案 3 :(得分:0)

修改生成的java类,我不同意。 不允许所有可能的xsd格式,我不同意。

Thanx对你所有解释的链接,这是我编写的代码,以便使用Annotation Introspection来处理这两种情况。它适用于输出和输入,并且(根据我的口味)更通用:

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

答案 4 :(得分:0)

我有同样的问题。 JAXB unmarshaller.unmarshal返回JAXBElement<MyObject>而不是期望的MyObject

我找到并删除了@XmlElementDecl。问题解决了。