Java – optional part of jax-ws response message
TL; Dr: how can I have an optional < part > in response to < message > for WSDL service
I am:
>Locate an existing service > write a client to talk to the service > implement the service definition as a java interface
Problem: depending on the version of the service, there may be an additional element in the response body element
Using the following service definition, I can locate the V1 of the service:
<message name="CreateResponse">
<part name="ResourceCreated" element="ns7:ResourceCreated" />
</message>
This is used with V2 of the service:
<message name="CreateResponse">
<part name="ResourceCreated" element="ns7:ResourceCreated" />
<part name="Shell" element="ns8:Shell" />
</message>
Question: how to use the same service definition to locate two versions? I really don't need the second element, so just ignore it
Details:
>The service is windows remote management service. > I'm writing a java client to locate it. > This code is in https://github.com/cloudsoft/winrm4j Provide > when talking with Windows 7, the create response contains a responsecreated element. > When talking to windows 2012, the create response contains two elements – responsecreated and shell
Solution
I don't believe there is a clean solution to this problem - it's impossible to mark the elements in < part > < message > as optional
The solution in this case is to remove the additional element before it reaches the Jax - WS parser This can be done by creating CXF interceptors or Jax - WS handlers and manipulating the response XML
To create a jax-ws handler:
public class StripHandler implements SOAPHandler<SOAPMessageContext> {
@Override
public boolean handleMessage(SOAPMessageContext context) {
boolean isResponse = Boolean.FALSE.equals(context.get (MessageContext.MESSAGE_OUTBOUND_PROPERTY));
if (isResponse) {
QName action = (QName) context.get(SOAPMessageContext.WSDL_OPERATION);
if ("Create".equals(action.getLocalPart())) {
Iterator<?> childIter = getBodyChildren(context);
while(childIter.hasNext()) {
SOAPElement el = (SOAPElement) childIter.next();
if ("Shell".equals(el.getLocalName())) {
childIter.remove();
}
}
}
}
return true;
}
private Iterator<?> getBodyChildren(SOAPMessageContext context) {
try {
SOAPEnvelope envelope = context.getMessage().getSOAPPart().getEnvelope();
SOAPBody body = envelope.getBody();
return body.getChildElements();
} catch (SOAPException e) {
throw new IllegalStateException(e);
}
}
@Override
public boolean handleFault(SOAPMessageContext context) {return true;}
@Override
public void close(MessageContext context) {}
@Override
public Set<QName> getHeaders() {return null;}
}
Register jax-ws handler:
To declare
Create handlers next to the service interface XML file:
<handler-chains xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee">
<handler-chain>
<handler>
<handler-name>StripHandlerr</handler-name>
<handler-class>fully.qualified.StripHandler</handler-class>
</handler>
</handler-chain>
</handler-chains>
And attach it to the service definition with the annotation @ handlerchain (file = "handlers. XML")
programming
This is an alternative approach that does not require additional XML files
((BindingProvider)service).getBinding().setHandlerChain(Arrays.<Handler>asList(new StripHandler());
