使用 JAXB 和 Any 进行序列化 [英] Serializing with JAXB and the Any
问题描述
我有一个定义以下类型的架构:
I have a schema that defines the following type:
<xsd:complexType name="Payload">
<xsd:sequence>
<xsd:any namespace="##any" minOccurs="0" maxOccurs="unbounded" processContents="lax"/>
</xsd:sequence>
</xsd:complexType>
这会创建一个像这样的对象:
And that creates an object like so:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Payload", propOrder = {
"any"
})
public class Payload {
@XmlAnyElement(lax = true)
protected List<Object> any;
}
现在我尝试将另一个生成的 JAXB 对象添加到该 Payload,执行如下操作:
Now I try adding another generated JAXB object to that Payload doing something like this:
Class payloadClass = ...;
JAXBContext context = JAXBContext.newInstance( WrapperRequest.class, payloadClass);
...
marshaller.marshal( wrappedRequest );
但是我遇到了一个可怕的异常,看起来它永远不会工作,所以我决定先将有效负载对象序列化为 XML,然后将其作为字符串添加到有效负载中.
But I get a terrible exception that looks like it'll never work so I decide to serialize the payload object to XML first then add that as a string in the payload.
StringWriter writer = new StringWriter();
JAXBContext context = JAXBContext.newInstance( sdoRequest.getClass() );
Marshaller marshaller = context.createMarshaller();
marshaller.marshal(new JAXBElement(new QName("uri", sdoRequest.getClass().getSimpleName()), sdoRequest.getClass(), sdoRequest), writer);
payload.getAny().add( writer.toString() );
这会因java.lang.String"不包含@XmlRootElement 的异常而爆炸.
And this blows up with an exception saying "java.lang.String" does not contain an @XmlRootElement.
那么 xs:any 将如何与 JAXB 一起使用?似乎什么都不想工作,因为 JAXB 将 Payload 转换为 Object,并且它不会序列化 Object 中的任何内容.这一切都在 Axis2 中,因此达到这一点非常具有挑战性.
So how will the use of xs:any ever work with JAXB? Nothing seems to want to work because JAXB turns the Payload into Object, and it won't serialize just anything in Object. This is all inside Axis2 as well so it's been very challenging to get to this point.
推荐答案
下面我将演示 JAXB (JSR-222) 和 any
以一个例子:
Below I will demonstrate JAXB (JSR-222) and any
with an example:
有效载荷
any
属性用 @XmlAnyElement(lax=true)
注释.这意味着对于该属性,如果元素通过 @XmlRootElement
或 @XmlElementDecl
与类关联,则将使用相应对象的实例来填充该属性,否则该元素将被设置为 org.w3c.dom.Element
的一个实例.
The any
property is annotated with @XmlAnyElement(lax=true)
. This means that for that property if an element is associated with a class via @XmlRootElement
or @XmlElementDecl
then an instance of the corresponding object will be used to populate the property if not the element will be set as an instance of org.w3c.dom.Element
.
package forum13941747;
import java.util.List;
import javax.xml.bind.annotation.*;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Payload", propOrder = {
"any"
})
public class Payload {
@XmlAnyElement(lax = true)
protected List<Object> any;
}
Foo
下面是一个用 @XmlRootElement
注释的类的例子.
Below is an example of a class annotated with @XmlRootElement
.
package forum13941747;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Foo {
}
条形
下面是一个没有 @XmlRootElement
注释的类的例子.在这个用例中,我们将利用 @XmlElementDecl
注释在用 @XmlRegistry
注释的工厂类(通常称为 ObjectFactory
)上.
Below is an example of a class without the @XmlRootElement
annotation. In this use case we will leverage the @XmlElementDecl
annotation on a factory class (usually called ObjectFactory
) annotated with @XmlRegistry
.
package forum13941747;
public class Bar {
}
对象工厂
以下是为 Bar
类指定 @XmlElementDecl
注释的示例.
Below is an example of specifying an @XmlElementDecl
annotation for the Bar
class.
package forum13941747;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.*;
import javax.xml.namespace.QName;
@XmlRegistry
public class ObjectFactory {
@XmlElementDecl(name="bar")
public JAXBElement<Bar> createBar(Bar bar) {
return new JAXBElement<Bar>(new QName("bar"), Bar.class, bar);
}
}
input.xml
以下是我们将用于此示例的输入文档.有 3 个元素对应于 any
属性.第一个对应于 Foo
类上的 @XmlRootElement
注释.第二个对应于 Bar
类的 @XmlElementDecl
注释,第三个不对应于任何域类.
Below is the input document we'll use for this example. There are 3 elements that correspond to the any
property. The first corresponds to the @XmlRootElement
annotation on the Foo
class. The second corresponds to the @XmlElementDecl
annotation for the Bar
class and the third does not correspond to any of the domain classes.
<?xml version="1.0" encoding="UTF-8"?>
<payload>
<foo/>
<bar/>
<other/>
</payload>
演示
在下面的演示代码中,我们将解组输入文档,然后在生成的 any
属性中输出对象的类,然后将 payload
对象编组回 XML.
In the demo code below we will unmarshal the input document, then output the classes of the objects in the resulting any
property and then marshal the payload
object back to XML.
package forum13941747;
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Payload.class, Foo.class, ObjectFactory.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum13941747/input.xml");
Payload payload = (Payload) unmarshaller.unmarshal(xml);
for(Object o : payload.any) {
System.out.println(o.getClass());
}
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(payload, System.out);
}
}
输出
以下是运行演示代码的输出.请注意与 any
属性中的对象对应的类.foo
元素成为 Foo
类的一个实例.bar
元素变成了 JAXBElement
的一个实例,它保存了一个 Bar
的实例.other
元素成为了 org.w3c.dom.Element
的一个实例.
Below is the output from running the demo code. Note the classes corresponding to the objects in the any
property. The foo
element became an instance of the Foo
class. The bar
element became an instance of JAXBElement
that holds an instance of Bar
. The other
element became an instance of org.w3c.dom.Element
.
class forum13941747.Foo
class javax.xml.bind.JAXBElement
class com.sun.org.apache.xerces.internal.dom.ElementNSImpl
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<payload>
<foo/>
<bar/>
<other/>
</payload>
这篇关于使用 JAXB 和 Any 进行序列化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!