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