1
votes

I am currently working on an implementation of the WS-Discovery specification for a device that should be discoverable by ONVIF compliant clients (e.g. video management systems). For marshaling the Java objects and wrapping them into a SOAP envelope I am using the approach described in this example. As you can see, in this example a Java object is marshaled into a document using the JAXB marshaller implementation, added to the body part of a SOAPMessage Object and then the SOAPMessage is written to a ByteArrayOutputStream.

With this approach I am currently producing messages in the following form (e.g. ProbeMatches response to Probe requests):

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

As you can see, the namespace declaration for WS-Addressing is there twice, once in the envelope and once in the ProbeMatches tag. Also I would like to move the namespace declaration from the ProbeMatches tag up to the envelope. So, what I actually want to achieve is the following:

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

How can I achieve that with JAXB and with respect to the mentioned example using SOAPMessage? The problem is, that the SOAPMassege does not seem to recognize the namespace declarations that are already present in the marshaled body part. I am also open to a completely different approach for marshalling.

As additional information, here is the structure of the ProbeMatchesType and the ProbeMatchType classes, which are being marshaled (I manually added the @XmlRootElement annotation to the ProbeMatchesType, the rest was generated from the official ONVIF WSDL files):

@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>();

    ...
}

Thanks in advance for any help!

Update

In my current approach when I remove the @XmlRootElement from the ProbeMatchesType class, I get the following exception:

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)

This happens, because currently the ProbeMatchesType object is actually really the root object for the XML marshaling. The marshaled document object is later-on added to the body part of a SOAPMessage object, which wraps everything into a SOAP envelope when it is finally written to the ByteArrayOutputStream (like you can see in the example that I already linked in the beginning of my question).

1

1 Answers

0
votes

Try removing the @XmlRootElement(name = "ProbeMatches") from ProbeMatchesType class.

@XmlRootElement should be used for top level class, in your case top level class is Envelope.