JAXB unmarshaller.unmarshal何时返回JAXBElement 或MySchemaObject?

我有两个代码,在两个不同的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(); 

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

如果根元素唯一对应于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 = ""; 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 

它取决于根元素的类上是否存在XmlRootElement注释 。

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

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

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

您可以使用自定义文件自定义此匿名类型的类名。 例如,创建一个bindings.xjc文件,如下所示:

        

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

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

看看相关的问题(有很多好的提示): 尝试解组xml时的类强制转换exception?

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

谢谢所有解释的链接,这是我编写的代码,以便使用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(); } } 

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

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