SOAP service response cannot be mapped
Asked Answered
S

2

6

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.

Shift answered 6/5, 2015 at 14:14 Comment(0)
S
1

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

Signally answered 11/5, 2015 at 21:5 Comment(1)
PersonnelInfoRequest is being sent out wrapped in PersonnelInfo but yes, the result is a naked PersonnelInfoResponse. From what I could also find on Google that does seem to be the problem. Thank you for confirming that. Alas, I have no control over the service so I refactored the code and used Spring-WS to make the calls. Now it works.Shift
J
0

There is one obvious difference between your 2 calls :

You should try to remove operationName = "PersonnelInfo" from your second call which is not present in the first working one.

Jesicajeske answered 8/5, 2015 at 9:52 Comment(1)
That doesn't work because, as I understand, if it's missing then JAX-WS tries to parse the operation name from the method signature. Since the method starts with a lowercase p then it fails. I updated my original post with the .wsdl definitions, as you can also see they are practically identical in their structure.Shift

© 2022 - 2024 — McMap. All rights reserved.