Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SOAP service response cannot be mapped

This problem has had me stumped for almost two days now, I really need some help figuring it out.

I have used wsimport to generate code from two different .wsdl files for a Java project.

The first service works just fine but for some reason the response from the second service cannot be unmarshalled to a response object.

Working service:

@WebMethod(action = "[actionName]")
@WebResult(name = "getSimpleCompanyInfoResponse", partName = "getSimpleCompanyInfoResponse")
public GetSimpleCompanyInfoResponse getSimpleCompanyInfo(
        @WebParam(name = "getSimpleCompanyInfoRequest", partName = "getSimpleCompanyInfoRequest") GetSimpleCompanyInfoRequest getSimpleCompanyInfoRequest);

Response POJO:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "getSimpleCompanyInfoResponse", propOrder = {
    //variables
})
public class GetSimpleCompanyInfoResponse {
    //variables
}

Response XML:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="[namespaceUri]" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <SOAP-ENV:Body>
        <ns1:getSimpleCompanyInfoResponse>
            <getSimpleCompanyInfoResponse>
                //variables
            </getSimpleCompanyInfoResponse>
        </ns1:getSimpleCompanyInfoResponse>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

NOT working service:

@WebMethod(operationName = "PersonnelInfo", action = "[actionName]")
@WebResult(name = "PersonnelInfoResponse", partName = "PersonnelInfoResponse")
public PersonnelInfoResponse personnelInfo(
@WebParam(name = "PersonnelInfoRequest", partName = "PersonnelInfoRequest") PersonnelInfoRequest personnelInfoRequest);

Response POJO:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "PersonnelInfoResponse", propOrder = {
    //variables
})
public class PersonnelInfoResponse {
    //variables
}

Response XML:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="[namespaceUri]" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <SOAP-ENV:Body>
        <ns1:PersonnelInfoResponse>
            //variables
        </ns1:PersonnelInfoResponse>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Using -Dcom.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.dump=true or monitoring with Wireshark I can see the Response envelope from the second service coming through just fine and unmarshalling doesn't throw any exceptions but in the end PersonnelInfoResponse is null.

The only difference I can see is that the second service response payload in the XML is missing the outer element which seems to be the problem. However, I do not know how to "fix" it so it doesn't look for the outer element.

If anything was unclear or missing please let me know and I'll try to give you all the information.

EDIT:

No, I unfortunately don't have any control over the service itself, I only have the .wsdl and .xsd.

I'm calling the service like this:

ReportsControllerPortType port = new ReportsControllerService().getReportsControllerPort();

PersonnelInfoRequest request = new PersonnelInfoRequest();
//fill the required fields in the request, username, password, etc.

PersonnelInfoResponse response = port.personnelInfo(request);

The client-side service stubs (ReportsControllerService & ReportsControllerPortType) are also automatically generated by wsimport according to the .wsdl and .xsd.

EDIT 2:

Removing the operation name doesn't work, the service fails to initialize. Following are the definitions from both .wsdl-s:

Working service:

<wsdl:message name="getSimpleCompanyInfoRequest">
    <wsdl:part name="getSimpleCompanyInfoRequest" type="tns:getSimpleCompanyInfoRequest" />
</wsdl:message>
<wsdl:message name="getSimpleCompanyInfoResponse">
    <wsdl:part name="getSimpleCompanyInfoResponse" type="tns:getSimpleCompanyInfoResponse" />
</wsdl:message>

<wsdl:portType name="MonitoringControllerPortType">
    <wsdl:operation name="getSimpleCompanyInfo">
        <wsdl:input message="tns:getSimpleCompanyInfoRequest" />
        <wsdl:output message="tns:getSimpleCompanyInfoResponse" />
    </wsdl:operation>
</wsdl:portType>

<wsdl:binding name="MonitoringControllerBinding" type="tns:MonitoringControllerPortType">
    <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" />

    <wsdl:operation name="getSimpleCompanyInfo">
        <soap:operation soapAction="[domain]/#getSimpleCompanyInfo" style="rpc" />
        <wsdl:input>
            <soap:body use="literal" namespace="[namespaceUri]" />
        </wsdl:input>
        <wsdl:output>
            <soap:body use="literal" namespace="[namespaceUri]" />
        </wsdl:output>
    </wsdl:operation>
</wsdl:binding>

<wsdl:service name="MonitoringControllerService">
    <wsdl:port name="MonitoringControllerPort" binding="tns:MonitoringControllerBinding">
        <soap:address location="[serviceUri]" />
    </wsdl:port>
</wsdl:service>

Not working service:

<wsdl:message name="PersonnelInfoRequest">
    <wsdl:part name="PersonnelInfoRequest" type="tns:PersonnelInfoRequest" />
</wsdl:message>
<wsdl:message name="PersonnelInfoResponse">
    <wsdl:part name="PersonnelInfoResponse" type="tns:PersonnelInfoResponse" />
</wsdl:message>

<wsdl:portType name="ReportsControllerPortType">
    <wsdl:operation name="PersonnelInfo">
        <wsdl:input message="tns:PersonnelInfoRequest" />
        <wsdl:output message="tns:PersonnelInfoResponse" />
    </wsdl:operation>
</wsdl:portType>

<wsdl:binding name="ReportsControllerBinding" type="tns:ReportsControllerPortType">
    <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" />
    <wsdl:operation name="PersonnelInfo">
        <soap:operation soapAction="[domain]/#PersonnelInfo" style="rpc" />
        <wsdl:input>
            <soap:body use="literal" namespace="[namespaceUri]" />
        </wsdl:input>
        <wsdl:output>
            <soap:body use="literal" namespace="[namespaceUri]" />
        </wsdl:output>
    </wsdl:operation>
</wsdl:binding>

<wsdl:service name="ReportsControllerService">
    <wsdl:port name="ReportsControllerPort" binding="tns:ReportsControllerBinding">
        <soap:address location="[serviceUri]" />
    </wsdl:port>
</wsdl:service>

EDIT 3:

ReportsControllerService and MonitoringControllerService extend javax.xml.ws.Service and contain the definitions of the .wsdl schema location and namespace used. The service class returns a PortType object as you can see:

/**
 * This class was generated by the JAX-WS RI. JAX-WS RI 2.2.9-b130926.1035 Generated source version: 2.2
 */
@WebServiceClient(name = "ReportsControllerService", targetNamespace = "[namespaceUri]", wsdlLocation = "[wsdlUri]")
public class ReportsControllerService extends Service {

    @WebEndpoint(name = "ReportsControllerPort")
    public ReportsControllerPortType getReportsControllerPort() {
        return super.getPort(new QName("[namespaceUri]", "ReportsControllerPort"), ReportsControllerPortType.class);
    }
}

ReportsControllerPortType is an interface which contains methods for every operation endpoint that exists in the service

/**
 * This class was generated by the JAX-WS RI. JAX-WS RI 2.2.9-b130926.1035 Generated source version: 2.2
 */
@WebService(name = "ReportsControllerPortType", targetNamespace = "[namespaceUri]")
@SOAPBinding(style = SOAPBinding.Style.RPC)
@XmlSeeAlso({ObjectFactory.class})
public interface ReportsControllerPortType {

    @WebMethod(operationName = "PersonnelInfo", action = "[actionName]")
    @WebResult(name = "PersonnelInfoResponse", partName = "PersonnelInfoResponse")
    public PersonnelInfoResponse personnelInfo(
        @WebParam(name = "PersonnelInfoRequest", partName = "PersonnelInfoRequest") PersonnelInfoRequest personnelInfoRequest);
    }
}

The thing is, all of those classes are automatically generated by JAX-WS (as you can see from the comments) based on the .wsdl schema. The implementation is abstracted somewhere inside the JDK and I don't have control over that either. Yes, I can refactor the code so I bypass JAX-WS but as I understand it, this is supposed to be like a de facto standard way to consume .wsdl-based SOAP services.

The project uses Spring as a base-framework and I have already confirmed both services will work when I use Spring-WS instead so I can refactor but I want to understand why this way isn't working.

like image 730
rorschach Avatar asked May 06 '15 14:05

rorschach


1 Answers

I believe I may have found out why your webservice is misbehaving. According to the specification, an RPC webservice must fulfill the following criteria in its soap binding (i.e. the @SOAPBinding annotation you have there)

  1. A style of RPC: check

  2. A use of LITERAL: check

  3. A parameterStyle of WRAPPED: From the description you've given, it would appear that WRAPPED is not the case here, seeing as you're receiving a naked PersonnelInfoResponse (and possibly sending a naked PersonnelInfoRequest) without any wrapping indicates that the service itself is broken.

An excerpt from the JAX-WS spec:

Use of RPC style requires the use of WRAPPED parameter style. Deviations from this is an error

like image 179
kolossus Avatar answered Sep 30 '22 18:09

kolossus