【问题标题】:unexpected XML tag issue with Jax Ws clientJax Ws 客户端出现意外的 XML 标记问题
【发布时间】:2015-11-21 04:36:30
【问题描述】:

我正在使用供应商 Web 服务。使用 JDK6 wsimport 为供应商 WSDL 生成类。现在我正在尝试使用一个简单的 java 客户端类调用 Web 服务,并通过响应获取此异常。

非预期的 XML 标记。预期:{http://www.abcd.com/addressValidation/}validateAddressResponse 但发现:{}validateAddressResponse

供应商说尝试使用 Apache Axis 生成的类,它工作正常。我注意到的是 JaxWS 会自动将命名空间附加/绑定到请求中的每个元素,并且还期望响应元素中的命名空间。

生成的接口是

    @WebService(name = "AddressStandardize", targetNamespace = "http://www.abcd.com/addressValidation/")
@XmlSeeAlso({
    com.abcd.ObjectFactory.class
})
public interface AddressStandardize {

    @WebMethod(action = "http://www.abcd.com/standardizeAddress")
    @RequestWrapper(localName = "validateAddress", targetNamespace = "", className = "com.abcd.ValidateAddress")
    @ResponseWrapper(localName = "validateAddressResponse", targetNamespace = "", className = "com.abcd.ValidateAddressResponse")
    public void standardizeAddress(
    ...
    ...
    ...
    );
}

我猜 Jax-WS 将此目标命名空间附加到 validateAddress 和 validateAddressResponse 元素。

如何避免将目标命名空间绑定到 validateAddressResponse 元素,这样它就不会期望得到响应。请帮忙!

Jax WS 生成的请求:

    <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
    <S:Header>
        <ns2:id xmlns:ns2="http://www.abcd.com/addressValidation/">PSA</ns2:id>
    </S:Header>
    <S:Body>
        <ns2:validateAddress xmlns:ns2="http://www.abcd.com/addressValidation/">
            <arg1>
                <addresslineone>126 corbin st</addresslineone>
                <addresslinetwo/>
                <addresslinethree/>
                <city>jersey city</city>
                <state>NJ</state>
                <postalcode/>
                <country/>
                <isocountrycode>US</isocountrycode>
            </arg1>
        </ns2:validateAddress>
    </S:Body>
</S:Envelope>

返回响应:

    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xyz="http://www.abcd.com/xyz">
    <soapenv:Header xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <xyz:id>PSA</xyz:id>
    </soapenv:Header>
    <soapenv:Body xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <validateAddressResponse xsi:noNamespaceSchemaLocation="addressValidation.xsd">
            <validateAddressReturn>
                ...
                ...
                ...
            </validateAddressReturn>
            <ResponseStatus>
                <StatusCode>SUCCESS</StatusCode>
            </ResponseStatus>
        </validateAddressResponse>
    </soapenv:Body>
</soapenv:Envelope>

此响应带有此异常... 意外的 XML 标记。预期:{http://www.abcd.com/addressValidation/}validateAddressResponse 但发现:{}validateAddressResponse

【问题讨论】:

    标签: jax-ws


    【解决方案1】:

    我也遇到了这个问题,但无法找到告诉 JAX-WS 不要期望命名空间的方法。但是,我能够通过预处理 SOAPHandler 中的响应并手动向 XML 元素添加命名空间(通过给它一个包含命名空间声明的新 QName)来解决它。

    MyHandler.java:

    public class MyHandler implements SOAPHandler<SOAPMessageContext> {
        @Override
        public void close(MessageContext context) { 
        }
    
        @Override
        public boolean handleMessage(SOAPMessageContext context) {
            //Don't intercept outbound messages (SOAP Requests)
            if ((Boolean)context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY)) {return true;}
    
            SOAPMessage message = context.getMessage();
            try {
                SOAPBody body = message.getSOAPBody();
                Iterator<SOAPElement> bodyIterator = body.getChildElements();
                SOAPElement responseElement = bodyIterator.next();
                responseElement.setElementQName(new QName("http://www.theserver.com/cmdb_rel_ci", origGetRecordsResponse.getLocalName(), "cmdb"));
            } catch (Exception e) {e.printStackTrace();}
            return true;
        }
    
        @Override
        public boolean handleFault(SOAPMessageContext context) {
            return false;
        }
    
        @Override
        public Set<QName> getHeaders() {
            return Collections.emptySet();
        }
    }
    

    然后我只需要在我的主类中使用以下代码将我的 Handler 添加到 HandlerChain,它就可以工作了。

    Binding binding = ((BindingProvider)port).getBinding();
    List<Handler> handlers = binding.getHandlerChain();
    handlers.add(new MyHandler());
    binding.setHandlerChain(handlers);
    

    【讨论】: