没有由JAXB生成的@XmlRootElement

我试图从FpML(Finanial产品标记语言)版本4.5生成Java类。 一吨代码生成,但我不能使用它。 试图序列化一个简单的文件,我得到这个:

javax.xml.bind.MarshalException - with linked exception: [com.sun.istack.SAXException2: unable to marshal type "org.fpml._2008.fpml_4_5.PositionReport" as an element because it is missing an @XmlRootElement annotation] 

实际上没有类有@XmlRootElement注解,那么我可能做错了什么? 我将xjc(JAXB 2.1)指向fpml-main-4-5.xsd,然后包含所有types。

为了将其他人已经陈述或暗示的东西联系在一起,JAXB XJC决定是否将@XmlRootElement注释放在生成的类上的规则并不是微不足道的( 参见本文 )。

存在@XmlRootElement是因为JAXB运行时需要某些信息来编组/给一个给定对象,尤其是XML元素名称和命名空间。 你不能把任何旧的物体传递给Marshaller。 @XmlRootElement提供了这个信息。

注释只是一个方便,但是 – JAXB不需要它。 另一种方法是使用JAXBElement包装器对象,它提供与@XmlRootElement相同的信息,但采用对象的forms,而不是注释。

但是,由于您需要知道XML元素名称和命名空间,所以业务逻辑通常不会知道JAXBElement对象是不是很容易构造。

谢天谢地,当XJC生成类模型时,它也会生成一个名为ObjectFactory的类。 这在一定程度上是为了向后兼容JAXB v1,但是它也可以作为XJC放置生成的工厂方法的地方,这些工厂方法在您自己的对象周围创buildJAXBElement包装器。 它为你处理XML名称和命名空间,所以你不必担心它。 您只需要查看ObjectFactory方法(对于大型模式,可以有数百个)来查找所需的方法。

这已经在上面已经链接的博客文章的底部提到,但是这对我来说就像是一种享受:

 Marshaller marshaller = jc.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); marshaller.marshal(new JAXBElement<MyClass>(new QName("uri","local"), MyClass.class, myClassInstance), System.out); 

正如在上面的答案中提到的那样,如果在XSD中将其types定义为命名types,则不会在根元素上获得XMLRootElement,因为可以在XSD中的其他位置使用该命名types。 尝试使用匿名types,而不是:

 <xsd:element name="myRootElement" type="MyRootElementType" /> <xsd:complexType name="MyRootElementType"> ... </xsd:complexType> 

你将会拥有:

 <xsd:element name="myRootElement"> <xsd:complexType> ... <xsd:complexType> </xsd:element> 

如果使用Unmarshaller#unmarshall的2参数forms,则不需要@XmlRootElement解组。

所以,如果不这样做:

 UserType user = (UserType) unmarshaller.unmarshal(new StringReader(responseString)); 

应该这样做:

 JAXBElement<UserType> userElement = unmarshaller.unmarshal(someSource, UserType.class); UserType user = userElement.getValue(); 

后面的代码将不需要在UserType类级别的@XmlRootElement注释。

乔的回答(乔Jun 29 '09在17:26)为我做。 简单的答案是,如果编组JAXBElement,则缺less@XmlRootElement批注是没有问题的。 让我感到困惑的是生成的ObjectFactory有两个createMyRootElement方法 – 第一个不带参数,给出解包对象,第二个带解包对象并返回它包装在JAXBElement中,然后编组JAXBElement工作正常。 下面是我使用的基本代码(我是新手,非常抱歉,如果代码在这个回复中没有正确格式化),很大程度上是从链接文本中删除:

 ObjectFactory objFactory = new ObjectFactory(); MyRootElement root = objFactory.createMyRootElement(); ... // Set root properties ... if (!writeDocument(objFactory.createMyRootElement(root), output)) { System.err.println("Failed to marshal XML document"); } ... private boolean writeDocument(JAXBElement document, OutputStream output) { Class<?> clazz = document.getValue().getClass(); try { JAXBContext context = JAXBContext.newInstance(clazz.getPackage().getName()); Marshaller m = context.createMarshaller(); m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); m.marshal(document, output); return true; } catch (JAXBException e) { e.printStackTrace(System.err); return false; } } 

您可以使用来自如何为XSD中的基本types生成@XmlRootElement类的绑定来解决此问题? 。

这是Maven的一个例子

  <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>jaxb2-maven-plugin</artifactId> <version>1.3.1</version> <executions> <execution> <id>xjc</id> <goals> <goal>xjc</goal> </goals> </execution> </executions> <configuration> <schemaDirectory>src/main/resources/xsd</schemaDirectory> <packageName>com.mycompany.schemas</packageName> <bindingFiles>bindings.xjb</bindingFiles> <extension>true</extension> </configuration> </plugin> 

这里是binding.xjb文件的内容

 <?xml version="1.0"?> <jxb:bindings version="1.0" xmlns:jxb="http://java.sun.com/xml/ns/jaxb" xmlns:xjc= "http://java.sun.com/xml/ns/jaxb/xjc" jxb:extensionBindingPrefixes="xjc" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <jxb:bindings schemaLocation="path/to/myschema.xsd" node="/xs:schema"> <jxb:globalBindings> <xjc:simple/> </jxb:globalBindings> </jxb:bindings> </jxb:bindings> 

它也不适合我们。 但是我们确实find了一个被广泛引用的文章,增加了一些背景知识……为了下一个人的目的,我将在这里链接到http://weblogs.java.net/blog/kohsuke/archive/2006/03 /why_does_jaxb_p.html

如你所知,答案是使用ObjectFactory()。 这是一个为我工作的代码示例:)

 ObjectFactory myRootFactory = new ObjectFactory(); MyRootType myRootType = myRootFactory.createMyRootType(); try { File file = new File("./file.xml"); JAXBContext jaxbContext = JAXBContext.newInstance(MyRoot.class); Marshaller jaxbMarshaller = jaxbContext.createMarshaller(); //output pretty printed jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); JABXElement<MyRootType> myRootElement = myRootFactory.createMyRoot(myRootType); jaxbMarshaller.marshal(myRootElement, file); jaxbMarshaller.marshal(myRootElement, System.out); } catch (JAXBException e) { e.printStackTrace(); } 

使用Maven构build,您可以添加@XmlRootElement注释

带有“ jaxb2-basics-annotate ”插件。

查看更多信息:请参阅

configurationMaven使用JAXB从XML Schema生成类

和JAXB XJC代码生成

你有没有尝试像这样改变你的xsd?

 <!-- create-logical-system --> <xs:element name="methodCall"> <xs:complexType> ... </xs:complexType> </xs:element> 

如果我的这个问题的经验给人一个尤里卡! 时刻..我会添加以下内容:

当我使用IntelliJ的“从实例文档生成xsd”菜单选项生成的xsd文件时,我也遇到了这个问题。

当我接受这个工具的所有默认值时,它生成一个xsd文件,当与jaxb一起使用时,生成不带@XmlRootElement的java文件。 在运行时,当我尝试编组时,得到了与此问题中讨论的相同的exception。

我回到了IntellJ工具,看到“Desgin Type”下拉菜单中的默认选项(当然,我不明白,但是如果我诚实的话,我还是不这样做)是:

devisetypes:

“本地元素/全球复杂types”

我改变了这个

“本地元素/types”

,现在它生成了一个(基本上)不同的xsd,与jaxb @XmlRootElement使用时生成了@XmlRootElement。 我不能说我明白了它的内在和外在,但它对我有效。

为了解决它,你应该configuration一个xml绑定,然后用wsimport进行编译,将generateElementProperty设置为false。

  <jaxws:bindings wsdlLocation="LOCATION_OF_WSDL" xmlns:jaxws="http://java.sun.com/xml/ns/jaxws" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:jxb="http://java.sun.com/xml/ns/jaxb" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"> <jaxws:enableWrapperStyle>false</jaxws:enableWrapperStyle> <jaxws:bindings node="wsdl:definitions/wsdl:types/xs:schema[@targetNamespace='NAMESPACE_OF_WSDL']"> <jxb:globalBindings xmlns:jxb="http://java.sun.com/xml/ns/jaxb" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xjc:generateElementProperty>false</xjc:generateElementProperty> </jxb:globalBindings> </jaxws:bindings> </jaxws:bindings> 

JAXBElement包装器适用于JAXB不生成@XmlRootElement情况。 这些包装在maven-jaxb2-plugin生成的ObjectFactory类中可用。 例如:

  public class HelloWorldEndpoint { @PayloadRoot(namespace = NAMESPACE_URI, localPart = "person") @ResponsePayload public JAXBElement<Greeting> sayHello(@RequestPayload JAXBElement<Person> request) { Person person = request.getValue(); String greeting = "Hello " + person.getFirstName() + " " + person.getLastName() + "!"; Greeting greet = new Greeting(); greet.setGreeting(greeting); ObjectFactory factory = new ObjectFactory(); JAXBElement<Greeting> response = factory.createGreeting(greet); return response; } } 
Interesting Posts