Java JAXB unmarshaller.unmarshal何时返回JAXBElement<;MySchemaObject>;还是一个神秘的对象?

Java JAXB unmarshaller.unmarshal何时返回JAXBElement<;MySchemaObject>;还是一个神秘的对象?,java,jaxb,unmarshalling,Java,Jaxb,Unmarshalling,我有两个代码,在两个不同的java项目中,执行几乎相同的操作(根据xsd文件解组Web服务的输入) 但在一个例子中,我应该这样写:(Input是一个占位符名称)(element是OMElement Input) 在另一个库中,我必须使用JAXBElement.getValue(),因为它是一个返回的JAXBElement,而简单(输入)转换只是崩溃: Input input = (Input)unmarshaller.unmarshal( element.getXMLStreamReader()

我有两个代码,在两个不同的java项目中,执行几乎相同的操作(根据xsd文件解组Web服务的输入)

但在一个例子中,我应该这样写:(Input是一个占位符名称)(element是OMElement Input)

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

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

您知道是什么导致了这样的差异吗?

您需要将正确的
@XMLRootElement
添加到JAXB生成的类中-它应该具有名称空间:

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

看看相关的问题(有很多好的提示):

这取决于根元素的类上是否存在

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

  • 如果根元素的类型是匿名类型->XmlRootElement注释将添加到生成的类中
  • 如果根元素的类型是顶级类型,则生成的类中将忽略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>

多亏了您的解释和链接,我写这篇文章是为了通过注释内省来处理这两种情况

这具有以下优点:

  • 不修改生成的java类
  • 允许所有可能的xsd格式
它既适用于输出,也适用于输入,我认为它更通用:

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

如果根元素唯一地对应于一个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());
    }

}

我也有同样的问题。JAXB unmarshaller.unmarshal返回一个
JAXBElement
,而不是所需的
MyObject


我找到并删除了
@xmlementdecl
。问题已经解决。

我认为查看XSD是有意义的,因为这取决于您是将其解组为SimpleType还是ComplexType。注意:名称空间也可以使用@javax.xml.bind.annotation.XmlSchema包注释指定(通常在package info.java中)您应该能够利用
JAXBIntrospector
类来简化代码。我添加了一个答案:出于好奇,为什么您要将您的包命名为
forum10243679
?@Saintali-我尝试为我的每个答案提供一个工作代码示例。如果需要重新访问,包名可以帮助我找到代码示例。我将前缀
forum
用于对应于公共论坛(如Stack Overflow)的代码示例(我使用bug前缀来重新创建bug),数字对应于URL中可以找到的问题ID。
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