我目前正致力于为符合ONVIF标准的客户端(例如视频管理系统)发现的设备实施WS-Discovery规范。为了编组Java对象并将它们包装到SOAP信封中,我使用this example中描述的方法。如您所见,在此示例中,使用JAXB marshaller实现将Java对象封送到文档中,添加到SOAPMessage对象的正文部分,然后将SOAPMessage写入ByteArrayOutputStream。
通过这种方法,我目前正在以下列形式生成消息(例如,ProbeMatches对Probe请求的响应):
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:wsa="http://www.w3.org/2005/08/addressing">
<env:Header>
<wsa:Action env:mustUnderstand="true">http://docs.oasis-open.org/ws-dd/ns/discovery/2009/01/ProbeMatches</wsa:Action>
<wsa:MessageID>urn:uuid:9a7e8bc4-d4aa-4269-bbd6-2414084f47fe</wsa:MessageID>
<wsa:To env:mustUnderstand="true">http://www.w3.org/2005/08/addressing/anonymous</wsa:To>
<wsa:RelatesTo>urn:uuid:f3e33900-6284-11e8-80b1-add204fec0a3</wsa:RelatesTo>
</env:Header>
<env:Body>
<ns2:ProbeMatches xmlns:ns2="http://docs.oasis-open.org/ws-dd/ns/discovery/2009/01" xmlns="http://www.w3.org/2005/08/addressing">
<ns2:ProbeMatch>
<EndpointReference>
<Address>urn:uuid:09edc0f4-d65c-3545-aba5-a59f86348521</Address>
<ReferenceParameters />
</EndpointReference>
<ns2:Types xmlns:dn="http://www.onvif.org/ver10/network/wsdl">dn:NetworkVideoTransmitter</ns2:Types>
<ns2:Scopes>onvif://www.onvif.org/name/MyDevice onvif://www.onvif.org/hardware/MyHardware onvif://www.onvif.org/location onvif://www.onvif.org/Profile/Streaming</ns2:Scopes>
<ns2:XAddrs>http://192.168.0.10:8080/onvif/device_service</ns2:XAddrs>
<ns2:MetadataVersion>1</ns2:MetadataVersion>
</ns2:ProbeMatch>
</ns2:ProbeMatches>
</env:Body>
</env:Envelope>
正如您所看到的,WS-Addressing的名称空间声明有两次,一次在信封中,一次在ProbeMatches标记中。另外,我想将命名空间声明从ProbeMatches标记移动到信封。 所以,我真正希望实现的目标如下:
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:wsd="http://docs.oasis-open.org/ws-dd/ns/discovery/2009/01">
<env:Header>
<wsa:Action env:mustUnderstand="true">http://docs.oasis-open.org/ws-dd/ns/discovery/2009/01/ProbeMatches</wsa:Action>
<wsa:MessageID>urn:uuid:9a7e8bc4-d4aa-4269-bbd6-2414084f47fe</wsa:MessageID>
<wsa:To env:mustUnderstand="true">http://www.w3.org/2005/08/addressing/anonymous</wsa:To>
<wsa:RelatesTo>urn:uuid:f3e33900-6284-11e8-80b1-add204fec0a3</wsa:RelatesTo>
</env:Header>
<env:Body>
<wsd:ProbeMatches>
<wsd:ProbeMatch>
<wsa:EndpointReference>
<wsa:Address>urn:uuid:09edc0f4-d65c-3545-aba5-a59f86348521</wsa:Address>
<wsa:ReferenceParameters />
</wsa:EndpointReference>
<wsd:Types xmlns:dn="http://www.onvif.org/ver10/network/wsdl">dn:NetworkVideoTransmitter</wsd:Types>
<wsd:Scopes>onvif://www.onvif.org/name/MyDevice onvif://www.onvif.org/hardware/MyHardware onvif://www.onvif.org/location onvif://www.onvif.org/Profile/Streaming</wsd:Scopes>
<wsd:XAddrs>http://192.168.0.10:8080/onvif/device_service</wsd:XAddrs>
<wsd:MetadataVersion>1</wsd:MetadataVersion>
</wsd:ProbeMatch>
</wsd:ProbeMatches>
</env:Body>
</env:Envelope>
如何使用JAXB以及使用SOAPMessage提到的示例实现这一点?问题是,SOAPMassege似乎没有识别已封送的正文部分中已存在的名称空间声明。我也对采用完全不同的编组方法持开放态度。
作为附加信息,这里是封送的ProbeMatchesType和ProbeMatchType类的结构(我手动将@XmlRootElement注释添加到ProbeMatchesType,其余部分是从官方ONVIF WSDL文件生成的):
@XmlRootElement(name = "ProbeMatches")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "ProbeMatchesType", propOrder = {
"probeMatch",
"any"
})
public class ProbeMatchesType {
@XmlElement(name = "ProbeMatch")
protected List<ProbeMatchType> probeMatch;
@XmlAnyElement(lax = true)
protected List<Object> any;
@XmlAnyAttribute
private Map<QName, String> otherAttributes = new HashMap<QName, String>();
...
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "ProbeMatchType", propOrder = {
"endpointReference",
"types",
"scopes",
"xAddrs",
"metadataVersion",
"any"
})
public class ProbeMatchType {
@XmlElement(name = "EndpointReference", namespace = "http://www.w3.org/2005/08/addressing", required = true)
protected W3CEndpointReference endpointReference;
@XmlList
@XmlElement(name = "Types")
protected List<QName> types;
@XmlElement(name = "Scopes")
protected ScopesType scopes;
@XmlList
@XmlElement(name = "XAddrs")
protected List<String> xAddrs;
@XmlElement(name = "MetadataVersion")
@XmlSchemaType(name = "unsignedInt")
protected long metadataVersion;
@XmlAnyElement(lax = true)
protected List<Object> any;
@XmlAnyAttribute
private Map<QName, String> otherAttributes = new HashMap<QName, String>();
...
}
提前感谢您的帮助!
更新
在我当前的方法中,当我从ProbeMatchesType类中删除@XmlRootElement时,我得到以下异常:
com.sun.istack.internal.SAXException2: unable to marshal type "org.xmlsoap.schemas.ws._2005._04.discovery.ProbeMatchesType" as an element because it is missing an @XmlRootElement annotation
at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.reportError(XMLSerializer.java:234)
at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.serializeRoot(ClassBeanInfoImpl.java:323)
at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:479)
at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:308)
这种情况发生了,因为当前ProbeMatchesType对象实际上实际上是XML编组的根对象。稍后将编组的文档对象添加到SOAPMessage对象的主体部分,当最终写入ByteArrayOutputStream时,它将所有内容包装到SOAP信封中(就像您在我已链接到的example中看到的那样)我问题的开头)。
答案 0 :(得分:0)
尝试从ProbeMatchesType类中删除@XmlRootElement(name =“ProbeMatches”)。
@XmlRootElement应该用于顶级类,在您的情况下,顶级类是Envelope。