我试图从FpML(金融产品标记语言)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,然后包括所有类型。
这个主题相当古老,但在企业业务上下文中仍然相关。我尽量避免接触xsds,以便将来可以轻松地更新它们。以下是我的解决方案。
1. 通常xjc:简单就足够了
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<jxb:bindings version="2.0" xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
jxb:extensionBindingPrefixes="xjc">
<jxb:globalBindings>
<xjc:simple/> <!-- adds @XmlRootElement annotations -->
</jxb:globalBindings>
</jxb:bindings>
它将主要创建用于导入xsd定义的XmlRootElements。
2. 划分您的jaxb2-maven-plugin执行
我曾遇到过,如果尝试从多个xsd定义生成类,而不是每个xsd生成一个执行定义,结果会有很大的不同。
因此,如果你有一个定义有多个<source>,那么只需要尝试拆分它们:
<execution>
<id>xjc-schema-1</id>
<goals>
<goal>xjc</goal>
</goals>
<configuration>
<xjbSources>
<xjbSource>src/main/resources/xsd/binding.xjb</xjbSource>
</xjbSources>
<sources>
<source>src/main/resources/xsd/definition1/</source>
</sources>
<clearOutputDir>false</clearOutputDir>
</configuration>
</execution>
<execution>
<id>xjc-schema-2</id>
<goals>
<goal>xjc</goal>
</goals>
<configuration>
<xjbSources>
<xjbSource>src/main/resources/xsd/binding.xjb</xjbSource>
</xjbSources>
<sources>
<source>src/main/resources/xsd/definition2/</source>
</sources>
<clearOutputDir>false</clearOutputDir>
</configuration>
</execution>
生成器不会捕捉到一个类可能就足够了的事实,因此每次执行都会创建自定义类。这正是我所需要的。
您可以使用如何在XSD中为基类型生成@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>
这是装订。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>
我只是在同一个问题上挣扎了一段时间,只是想发布我的最终结果,这对我来说很好。
所以基本问题是:
我必须从没有XmlRootElement注释的JAXB类实例生成xml字符串
这些类需要为编组过程绑定其他类
下面的类可以很好地解决这个问题:
public class Object2XmlConverter {
public static <T> String convertToString(final T jaxbInstance, final Class<?>... additionalClasses)
throws JAXBException {
final Class<T> clazz = (Class<T>) jaxbInstance.getClass();
final JAXBContext jaxbContext;
if (additionalClasses.length > 0) {
// this path is only necessary if you need additional classes to be bound
jaxbContext = JAXBContext.newInstance(addClassesToBeBound(clazz, additionalClasses));
} else {
jaxbContext = JAXBContext.newInstance(clazz);
}
final QName qname = new QName("", jaxbInstance.getClass().getSimpleName());
final JAXBElement<T> jaxbElement = new JAXBElement<T>(qname, clazz, null, jaxbInstance);
final Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
final StringWriter stringWriter = new StringWriter();
jaxbMarshaller.marshal(jaxbElement, stringWriter);
return stringWriter.toString();
}
private static <T> Class<?>[] addClassesToBeBound(final Class<T> clazz, final Class<?>[] additionalClasses) {
final Class<?>[] classArray = new Class<?>[additionalClasses.length + 1];
for (int i = 0; i < additionalClasses.length; i++) {
classArray[i] = additionalClasses[i];
}
classArray[classArray.length - 1] = clazz;
return classArray;
}
public static void main(final String[] args) throws Exception {
final Ns1TargetHeaderTyp dataTyp = ...;
System.out.println(convertToString(dataTyp));
}
}