使用JAXB和Any进行序列化
我有一个定义以下类型的模式:
这会创建一个像这样的对象:
@XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "Payload", propOrder = { "any" }) public class Payload { @XmlAnyElement(lax = true) protected List any; }
现在我尝试将另一个生成的JAXB对象添加到该Payload,执行以下操作:
Class payloadClass = ...; JAXBContext context = JAXBContext.newInstance( WrapperRequest.class, payloadClass); ... marshaller.marshal( wrappedRequest );
但是我得到一个可怕的exception看起来它永远不会工作所以我决定先将有效负载对象序列化为XML,然后将其作为字符串添加到有效负载中。
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() );
这会引发exception,说“java.lang.String”不包含@XmlRootElement。
那么如何使用xs:任何使用过的JAXB? 似乎没有什么可以工作,因为JAXB将Payload转换为Object,并且它不会仅仅对Object中的任何内容进行序列化。 这一切都在Axis2内部,因此达到这一点非常具有挑战性。
下面我将演示JAXB(JSR-222)以及any
一个示例:
有效载荷
any
属性使用@XmlAnyElement(lax=true)
注释@XmlAnyElement(lax=true)
。 这意味着对于该属性,如果元素通过@XmlRootElement
或@XmlElementDecl
与类关联,则相应对象的实例将用于填充属性,否则该元素将被设置为org.w3c.dom.Element
的实例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
富
下面是使用@XmlRootElement
注释的类的示例。
package forum13941747; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class Foo { }
酒吧
下面是没有@XmlRootElement
注释的类的@XmlRootElement
。 在这个用例中,我们将在使用@XmlElementDecl
注释的工厂类(通常称为ObjectFactory
)上利用@XmlElementDecl
批注。
package forum13941747; public class Bar { }
的ObjectFactory
下面是为Bar
类指定@XmlElementDecl
注释的示例。
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 createBar(Bar bar) { return new JAXBElement (new QName("bar"), Bar.class, bar); } }
input.xml中
下面是我们将用于此示例的输入文档。 有3个元素对应于any
属性。 第一个对应于Foo
类上的@XmlRootElement
注释。 第二个对应于Bar
类的@XmlElementDecl
注释,第三个对应于任何域类。
演示
在下面的演示代码中,我们将解组输入文档,然后在生成的any
属性中输出对象的类,然后将payload
对象封送回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
一个实例。
class forum13941747.Foo class javax.xml.bind.JAXBElement class com.sun.org.apache.xerces.internal.dom.ElementNSImpl
使用Object Factory来设置对象,如下所示,你不需要在DemoType.java中使用@XmlRootElement。
DemoType demoServiceRequest = new DemoType(); ObjectFactory obDemo = new ObjectFactory(); Request requestObject = new Request(); requestObject.setAny(obDemo.createDemo(demoServiceRequest));
并在Request.java中添加DemoType类,如@XmlSeeAlso({DemoType.class})