将类编组到XSD中:Anytype xml

时间:2013-04-25 16:02:48

标签: java xsd jax-ws marshalling

我的问题是我有一个MessageList类,它包含Message项,定义如下:

<xsd:complexType name="MessageType">
    <xsd:sequence>
        <xsd:any/>
    </xsd:sequence>
</xsd:complexType>
<xsd:element name="Message" type="tns:MessageType"/>
<xsd:complexType name="MessageListType">
    <xsd:sequence>
        <xsd:element name="Message" maxOccurs="unbounded"/>
    </xsd:sequence>
</xsd:complexType>
<xsd:element name="MessageList" type="tns:MessageListType"/>

我的消息类看起来像(我在这里遗漏了getter和setter)

public class Message
{
private String referenceId;
private String messageType;
private Timestamp createdTime;
private String transactionIdForeignKey;
private String xmlDetail;
}

当我尝试在我的servlet中封送这个类时,如:

         List<Message> retrievedMessages = new ArrayList<Message>();
         retrievedMessages.add(new Message);
         retrievedMessages.add(new Message);

         MessageListType messageListType = new MessageListType();
         for(Message message: retrievedMessages){
             messageListType.getMessage().add(message);
         }

我收到以下错误:

[#|2013-04-25T16:43:40.434+0100|WARNING|sun-appserver2.1|javax.enterprise.system.stream.err|_ThreadID=188;_ThreadName=p: thread-pool-1; w: 76;_RequestID=40c6fe10-c12f-4d0b-8912-c960381910d7;|
javax.xml.ws.WebServiceException: javax.xml.bind.MarshalException
 - with linked exception:
[javax.xml.bind.JAXBException: class uk.co.test.test.audit.model.Message nor any of its super class is known to this context.]
    at com.sun.xml.ws.message.jaxb.JAXBMessage.writePayloadTo(JAXBMessage.java:322)
    at com.sun.enterprise.jbi.serviceengine.comm.WrappedMessage.writePayloadTo(WrappedMessage.java:419)
    at com.sun.enterprise.jbi.serviceengine.comm.WrappedMessage$DocumentStyleWrapper.wrap(WrappedMessage.java:215)
    at com.sun.enterprise.jbi.serviceengine.comm.WrappedMessage.wrap(WrappedMessage.java:170)
    at com.sun.enterprise.jbi.serviceengine.comm.ProviderInOut.send(ProviderInOut.java:143)
    at com.sun.enterprise.jbi.serviceengine.bridge.transport.NMRServerConnection.sendResponse(NMRServerConnection.java:81)
    at com.sun.enterprise.jbi.serviceengine.bridge.transport.JBIAdapter$WSToolkit.handle(JBIAdapter.java:127)
    at com.sun.enterprise.jbi.serviceengine.bridge.transport.JBIAdapter.handle(JBIAdapter.java:86)
    at com.sun.enterprise.jbi.serviceengine.bridge.JAXWSMessageProcessor.doWork(JAXWSMessageProcessor.java:93)
    at com.sun.corba.ee.impl.orbutil.threadpool.ThreadPoolImpl$WorkerThread.run(ThreadPoolImpl.java:555)
Caused by: javax.xml.bind.MarshalException
 - with linked exception:
[javax.xml.bind.JAXBException: class uk.co.test.test.audit.model.Message nor any of its super class is known to this context.]
    at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:282)
    at com.sun.xml.bind.v2.runtime.BridgeImpl.marshal(BridgeImpl.java:100)
    at com.sun.xml.bind.api.Bridge.marshal(Bridge.java:141)
    at com.sun.xml.ws.message.jaxb.JAXBMessage.writePayloadTo(JAXBMessage.java:315)

任何人都知道为什么会这样吗?我猜测正在进行编组操作的servlet需要知道要查看哪个类,但我不知道该怎么做?

1 个答案:

答案 0 :(得分:5)

如果你想在班上做到那么精确,你需要在你的架构中更精确。

JAXB依赖于定义结构的模式,该结构与您希望JAXB解组的结构相同。

为了说明,让我们使用xjc编译您的模式 - 这将创建JAXB可以自动编写的类并对其进行注释。

这是班级:

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

    @XmlAnyElement(lax = true)
    protected Object any;

    public Object getAny() {
        return any;
    }

    public void setAny(Object value) {
        this.any = value;
    }

}

您可以看到所有JAXB都可以从您的架构中判断出您有一个MessageType类包含未知数量的内容 - <xsd:any/> - JAXB无法确定您,例如,有一个名为String的{​​{1}}需要设置。

如果您可以更改架构,请更新到

referenceId

告诉JAXB构建类所需的信息(在这种情况下<xsd:complexType name="MessageType"> <xsd:attribute name="referenceId" type="xsd:string"/> <xsd:attribute name="messageType" type="xsd:string"/> <xsd:attribute name="transactionIdForeignKey" type="xsd:string"/> <xsd:attribute name="xmlDetail" type="xsd:string"/> <xsd:attribute name="createdTime" type="xsd:integer"/> </xsd:complexType> TimeStamp - 要解组为long,您需要一些custom logic)。

生成的类现在类似于您自己的类:

TimeStamp

您可以看到xml中的属性直接映射到类中的字段。您还可以看到JAXB使用的注释,这些注释是not required,但有助于告诉它要映射到哪里。

如果您无法更改架构,则需要实施自定义逻辑以在@XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "MessageType") public class MessageType { @XmlAttribute(name = "referenceId") protected String referenceId; @XmlAttribute(name = "messageType") protected String messageType; @XmlAttribute(name = "transactionIdForeignKey") protected String transactionIdForeignKey; @XmlAttribute(name = "xmlDetail") protected String xmlDetail; @XmlAttribute(name = "createdTime") protected BigInteger createdTime; public String getReferenceId() { return referenceId; } public void setReferenceId(String value) { this.referenceId = value; } public String getMessageType() { return messageType; } public void setMessageType(String value) { this.messageType = value; } public String getTransactionIdForeignKey() { return transactionIdForeignKey; } public void setTransactionIdForeignKey(String value) { this.transactionIdForeignKey = value; } public String getXmlDetail() { return xmlDetail; } public void setXmlDetail(String value) { this.xmlDetail = value; } public BigInteger getCreatedTime() { return createdTime; } public void setCreatedTime(BigInteger value) { this.createdTime = value; } } 中搜索相关属性,然后手动映射。如果沿着这条路走下去,This应该让你开始。