簡體   English   中英

使用JAXB和Any進行序列化

[英]Serializing with JAXB and the Any

我有一個定義以下類型的模式:

<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:任何使用過的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<Object> any;

}

下面是使用@XmlRootElement注釋的類的示例。

package forum13941747;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Foo {

}

酒吧

下面是沒有@XmlRootElement注釋的類的@XmlRootElement 在這個用例,我們將充分利用@XmlElementDecl在工廠類(通常稱為注釋ObjectFactory帶注釋) @XmlRegistry

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<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>

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

如果您的有效負載是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();
}

//...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM