JAX-WS 响应消息中的可选部分
Optional part in JAX-WS response message
TL;DR: 我怎样才能在 wsdl 服务的响应 中有一个可选的 。
我是:
- 以现有服务为目标
- 编写客户端与服务对话
- 将 service definition 实现为 Java 接口[=52=]
问题:
根据服务的版本,响应正文元素中可能会有一个附加元素。
通过以下服务定义,我可以将服务的 v1 作为目标:
<message name="CreateResponse">
<part name="ResourceCreated" element="ns7:ResourceCreated" />
</message>
这一个适用于服务的 v2:
<message name="CreateResponse">
<part name="ResourceCreated" element="ns7:ResourceCreated" />
<part name="Shell" element="ns8:Shell" />
</message>
问题:
如何使用相同的服务定义来定位两个版本?我真的不需要第二个元素,所以忽略它就可以了。
详情:
- 服务是
Windows Remote Management Service
。
- 我正在编写一个 Java 客户端来定位它。
- 代码可在 https://github.com/cloudsoft/winrm4j
- 与 Windows 7 交谈时,
Create
响应包含单个 ResponseCreated
元素。
- 与 Windows 2012 交谈时,
Create
响应包含两个元素 - ResponseCreated
和 Shell
。
我不相信有一个干净的解决方案来解决这个问题 - 不可能将 中的 元素标记为可选。
这种情况下的解决方法是在附加元素到达 JAX-WS 解析器之前将其剥离。这可以通过创建 CXF 拦截器或 JAX-WS 处理程序并操纵响应 XML.
来完成
创建 JAX-WS 处理程序:
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;}
}
注册 JAX-WS 处理程序:
声明式
在服务接口旁边创建 handlers.xml
文件:
<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>
并使用注释 @HandlerChain(file = "handlers.xml")
将其附加到服务定义
以编程方式
这是一种替代方法,不需要额外的 xml 文件。
((BindingProvider)service).getBinding().setHandlerChain(Arrays.<Handler>asList(new StripHandler());
TL;DR: 我怎样才能在 wsdl 服务的响应
我是:
- 以现有服务为目标
- 编写客户端与服务对话
- 将 service definition 实现为 Java 接口[=52=]
问题: 根据服务的版本,响应正文元素中可能会有一个附加元素。
通过以下服务定义,我可以将服务的 v1 作为目标:
<message name="CreateResponse">
<part name="ResourceCreated" element="ns7:ResourceCreated" />
</message>
这一个适用于服务的 v2:
<message name="CreateResponse">
<part name="ResourceCreated" element="ns7:ResourceCreated" />
<part name="Shell" element="ns8:Shell" />
</message>
问题: 如何使用相同的服务定义来定位两个版本?我真的不需要第二个元素,所以忽略它就可以了。
详情:
- 服务是
Windows Remote Management Service
。 - 我正在编写一个 Java 客户端来定位它。
- 代码可在 https://github.com/cloudsoft/winrm4j
- 与 Windows 7 交谈时,
Create
响应包含单个ResponseCreated
元素。 - 与 Windows 2012 交谈时,
Create
响应包含两个元素 -ResponseCreated
和Shell
。
我不相信有一个干净的解决方案来解决这个问题 - 不可能将
这种情况下的解决方法是在附加元素到达 JAX-WS 解析器之前将其剥离。这可以通过创建 CXF 拦截器或 JAX-WS 处理程序并操纵响应 XML.
来完成创建 JAX-WS 处理程序:
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;}
}
注册 JAX-WS 处理程序:
声明式
在服务接口旁边创建 handlers.xml
文件:
<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>
并使用注释 @HandlerChain(file = "handlers.xml")
以编程方式
这是一种替代方法,不需要额外的 xml 文件。
((BindingProvider)service).getBinding().setHandlerChain(Arrays.<Handler>asList(new StripHandler());