本文介绍了使用JAXB和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:如何使用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.

推荐答案

下面我将演示和任何举个例子:

Below I will demonstrate JAXB (JSR-222) and any with an example:

有效负载

任何属性都使用 @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 {

}

Bar

以下是没有 @XmlRootElement 注释。在这个用例中,我们将利用<$注释的工厂类(通常称为 ObjectFactory )利用 @XmlElementDecl 注释。 c $ c> @XmlRegistry

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 {

}

ObjectFactory

以下是为<$指定 @XmlElementDecl 注释的示例c $ c> Bar class。

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个元素对应任何属性。第一个对应于 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>

演示

在下面的演示代码中,我们将解组输入文档,然后在结果任何属性中输出对象的类,然后封送有效负载对象返回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 其他元素成为 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进行序列化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-23 19:57