Java 使用JAXB和Any进行序列化

Java 使用JAXB和Any进行序列化,java,xsd,jaxb,axis2,Java,Xsd,Jaxb,Axis2,我有一个定义以下类型的模式: <xsd:complexType name="Payload"> <xsd:sequence> <xsd:any namespace="##any" minOccurs="0" maxOccurs="unbounded" processContents="lax"/> </xsd:sequence> </xsd:complexType> 但是我遇到了一个可怕的异常,看起来它永远不会

我有一个定义以下类型的模式:

<xsd:complexType name="Payload">
   <xsd:sequence>
      <xsd:any namespace="##any" minOccurs="0" maxOccurs="unbounded" processContents="lax"/>
   </xsd:sequence>
</xsd:complexType>
但是我遇到了一个可怕的异常,看起来它永远不会工作,所以我决定先将负载对象序列化为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将负载转换为对象,并且它不会序列化对象中的任何内容。这些都在Axis2内部,因此要达到这一点非常具有挑战性。

下面我将用一个示例演示和
任何

有效载荷

any
属性用
@xmlanyement(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;

}
package forum13941747;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Foo {

}

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

package forum13941747;

public class Bar {

}
ObjectFactory

下面是为
Bar
类指定
@xmlementdecl
注释的示例

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);
    }

}
演示

在下面的演示代码中,我们将解组输入文档,然后输出结果
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
元素成为持有
bar
实例的
JAXBElement
的实例。
other
元素成为了
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;

}
package forum13941747;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Foo {

}
class for um13941747.Foo
类javax.xml.bind.JAXBElement
类com.sun.org.apache.xerces.internal.dom.ElementNSImpl

使用对象工厂对对象进行mashalling,如下所示:DemoType.java中不需要@XmlRootElement

DemoType demoServiceRequest = new DemoType();
ObjectFactory obDemo = new ObjectFactory();  
Request requestObject = new Request();     
requestObject.setAny(obDemo.createDemo(demoServiceRequest));

并在Request.java中添加DemoType类,比如@xmlseealway({DemoType.class})

如果您的负载是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();
}

//...

当您尝试将包装对象添加到任何有效负载时,会出现什么异常?以下内容应该会有所帮助:这部分是如何将WSDL组合在一起的,我对此没有任何控制权。但是,包装请求在一个WSDL中定义,而有效负载中的请求在另一个WSDL中定义。它们都声明了BaseRequest,但生成代码时它们是不同的类。我得到了这个异常,两个类具有相同的XML类型名称{}BaseRequest。使用@XmlType.name和@XmlType.namespace为它们指定不同的名称。@BlaiseDoughan添加到负载的对象没有用@XmlRootElement注释,因为它是从WSDL生成的。我该怎么办?我添加的错误怎么办?看到简单的解决方法了吗?+一个是“我遇到了一个可怕的异常,看起来它永远不会工作”