我试图从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,然后包括所有类型。
万一我对这个问题的经验给了某人一个顿悟!时刻. .我补充如下:
在使用IntelliJ的“从实例文档中生成xsd”菜单选项生成的xsd文件时,我也遇到了这个问题。
当我接受该工具的所有默认值时,它生成了一个xsd文件,当与jaxb一起使用时,生成不带@XmlRootElement的java文件。在运行时,当我试图marshal时,我得到了与这个问题中讨论的相同的异常。
我回到IntellJ工具,在“设计类型”下拉菜单中看到了默认选项(当然我不明白…老实说,我现在也不知道)是:
设计类型:
“局部元素/全局复杂类型”
我把这个改为
“local文本/ types”
,现在它生成了一个(实质上)不同的xsd,当与jaxb一起使用时,生成了@XmlRootElement。我不能说我理解它的来龙去脉,但它对我很管用。
我只是在同一个问题上挣扎了一段时间,只是想发布我的最终结果,这对我来说很好。
所以基本问题是:
我必须从没有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));
}
}
经过两天的努力,我找到了解决问题的办法。您可以使用ObjectFactory类来解决没有@XmlRootElement的类。ObjectFactory重载了一些方法来将其包装在JAXBElement周围。
方法:1简单地创建对象。
方法:2将使用@JAXBElement包装对象。
总是使用Method:2来避免javax.xml.bind.MarshalException -与链接异常缺少@XmlRootElement注释。
请查看下面的示例代码
方法:1简单地创建对象
public GetCountry createGetCountry() {
return new GetCountry();
}
方法:2将使用@JAXBElement包装对象。
@XmlElementDecl(namespace = "my/name/space", name = "getCountry")
public JAXBElement<GetCountry> createGetCountry(GetCountry value) {
return new JAXBElement<GetCountry>(_GetCountry_QNAME, GetCountry.class, null, value);
}
工作代码示例:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
WebServiceTemplate springWSTemplate = context.getBean(WebServiceTemplate.class);
GetCountry request = new GetCountry();
request.setGuid("test_guid");
JAXBElement<GetCountryResponse> jaxbResponse = (JAXBElement<GetCountryResponse>)springWSTemplate .marshalSendAndReceive(new ObjectFactory().createGetCountry(request));
GetCountryResponse response = jaxbResponse.getValue();