【问题标题】:Serializing with JAXB and the Any使用 JAXB 和 Any 进行序列化
【发布时间】:2012-12-06 04:15:18
【问题描述】:

我有一个定义以下类型的架构:

<xsd:complexType name="Payload">
   <xsd:sequence>
      <xsd:any namespace="##any" minOccurs="0" maxOccurs="unbounded" processContents="lax"/>
   </xsd:sequence>
</xsd:complexType>

这会创建一个像这样的对象:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Payload", propOrder = {
    "any"
})
public class Payload {

    @XmlAnyElement(lax = true)
    protected List<Object> any;
}

现在我尝试将另一个生成的 JAXB 对象添加到该 Payload,执行如下操作:

Class payloadClass = ...;
JAXBContext context = JAXBContext.newInstance( WrapperRequest.class, payloadClass);
...
marshaller.marshal( wrappedRequest );

但是我遇到了一个可怕的异常,看起来它永远不会起作用,所以我决定先将有效负载对象序列化为 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() );

这会引发异常,说“java.lang.String”不包含@XmlRootElement。

那么 xs:any 将如何与 JAXB 一起使用呢?似乎什么都不想工作,因为 JAXB 将 Payload 转换为 Object,并且它不会序列化 Object 中的任何内容。这也都在 Axis2 内部,因此达到这一点非常具有挑战性。

【问题讨论】:

  • 当您尝试将包装的对象添加到 Any 有效负载时会出现什么异常?
  • 以下内容应该会有所帮助:blog.bdoughan.com/2010/08/…
  • 这部分是我对 WSDL 的控制为零的方式。但是,包装请求是在一个 WSDL 中定义的,而进入有效负载的请求是在另一个 WSDL 中定义的。它们都声明了一个 BaseRequest,但是在生成代码时它们是不同的类。我得到了这个异常两个类具有相同的 XML 类型名称 {esp.lala.com/2012/eo}BaseRequest.使用@XmlType.name 和@XmlType.namespace 为它们分配不同的名称。
  • @BlaiseDoughan 添加到有效负载的对象未使用 @XmlRootElement 进行注释,因为它是从 WSDL 生成的。我该怎么办?我添加的错误呢?看到有什么简单的方法吗?
  • +one 表示“我遇到了一个看起来永远无法工作的可怕异常”

标签: java xsd jaxb axis2


【解决方案1】:

下面我将通过一个例子来演示JAXB (JSR-222)any

有效载荷

any 属性使用@XmlAnyElement(lax=true) 进行注释。这意味着对于该属性,如果一个元素通过@XmlRootElement@XmlElementDecl 与一个类关联,则相应对象的实例将用于填充该属性,否则该元素将设置为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注解的类的例子。

package forum13941747;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Foo {

}

条形

下面是一个没有@XmlRootElement注解的类的例子。在这个用例中,我们将在使用 @XmlRegistry 注释的工厂类(通常称为 ObjectFactory)上利用 @XmlElementDecl 注释。

package forum13941747;

public class Bar {

}

对象工厂

下面是为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<Bar> createBar(Bar bar) {
        return new JAXBElement<Bar>(new QName("bar"), Bar.class, bar);
    }

}

input.xml

下面是我们将用于此示例的输入文档。有 3 个元素对应于 any 属性。第一个对应于Foo 类上的@XmlRootElement 注释。第二个对应于Bar 类的@XmlElementDecl 注释,第三个不对应于任何域类。

<?xml version="1.0" encoding="UTF-8"?>
<payload>
    <foo/>
    <bar/>
    <other/>
</payload>

演示

在下面的演示代码中,我们将解组输入文档,然后在生成的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
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<payload>
    <foo/>
    <bar/>
    <other/>
</payload>

【讨论】:

    【解决方案2】:

    使用 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})

    【讨论】:

      【解决方案3】:

      如果您的有效负载是 XML 字符串,我设法使用以下代码解决了同样的问题:

      import javax.xml.parsers.DocumentBuilderFactory;
      
      //...
      
      String XMLPAYLOAD = "...";
      
      Payload payload = new ObjectFactory().createPayload();
      try {
          payload.setAny(DocumentBuilderFactory
                 .newInstance()
                 .newDocumentBuilder()
                 .parse(new InputSource(new StringReader(XMLPAYLOAD)))
                 .getDocumentElement());
      } catch (Exception e) {
          e.printStackTrace();
      }
      
      //...
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-01-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多