Unexpected XML tag issue with Jax Ws client

jax-ws

I am consuming a vendor web service. Generated the classes using JDK6 wsimport for the vendor WSDL. Now I am trying to invoke the web service using a simple java client class and getting this exception with response.

unexpected XML tag. expected: {http://www.abcd.com/addressValidation/}validateAddressResponse but found: {}validateAddressResponse

The vendor says try with Apache Axis generated classes, it works fine. What I noticed is JaxWS automatically appends/binds namespace to each element in request and expecting the namespace in response element also.

The generated Interface is

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

I guess Jax-WS appending this target namespace to both validateAddress and validateAddressResponse elements.

How to avoid binding target namespace to validateAddressResponse element so that it wont expect back in response. Please help!

Jax WS generated request:

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

Return Response:

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

This response is coming with this exception…
unexpected XML tag. expected: {http://www.abcd.com/addressValidation/}validateAddressResponse but found: {}validateAddressResponse

Best Answer

I also ran into this issue, and was unable to find a way to tell JAX-WS not to expect a namespace. However, I was able to work around it by pre-processing the response in a SOAPHandler and manually adding a namespace to the XML element (by giving it a new QName that included a namespace declaration).

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

Then I just had to add my Handler to the HandlerChain with the following code in my main class, and it worked.

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