没有由 JAXB 生成的@XmlRootElement

2022-08-31 05:43:49

我正在尝试从FpML(Finanial Products Markup Language)版本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,然后包括所有类型。


答案 1

为了将其他人已经陈述或暗示的内容联系在一起,JAXB XJC 决定是否将注释放在生成的类上的规则并非易事(请参阅本文)。@XmlRootElement

@XmlRootElement存在是因为 JAXB 运行时需要某些信息来封送/取消封送给定对象,特别是 XML 元素名称和命名空间。你不能只是把任何旧物体传递给马歇尔。 提供此信息。@XmlRootElement

注释只是一种方便,但是 - JAXB不需要它。替代方法是使用包装器对象,它们提供与 相同的信息,但采用对象的形式,而不是注释。JAXBElement@XmlRootElement

但是,对象的构造很尴尬,因为您需要知道 XML 元素名称和命名空间,而业务逻辑通常不知道。JAXBElement

值得庆幸的是,当 XJC 生成类模型时,它还会生成一个名为 的类。这部分是为了向后兼容 JAXB v1,但它也是 XJC 放置生成的工厂方法的地方,这些方法围绕您自己的对象创建包装器。它为您处理 XML 名称和命名空间,因此您无需担心。您只需要查看方法(对于大型架构,可能有数百个方法)即可找到所需的方法。ObjectFactoryJAXBElementObjectFactory


答案 2

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

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

推荐