WebService can't handle request with SOAP Body not having a namespace prefix

28,205

A web service defines a contract that you must follow in order to call it. Only one message from the examples you posted matches that contract so that one works, the other doesn't.

In your first message you defined a default namespace (because of the xmlns attribute in the wrapper) and all your elements that don't undeclare it and that have no prefix are in the same namespace because they inherit it from their parent.

In your second message you have an explicit prefix declaration and only the wrapper is in that namespaces, the other elements are not in a namespace and don't inherit a default one from the parent (because of xmlns attribute missing).

As I said at the beginning, the web service defines a contract. It makes more sense to modify the clients to send the correct message instead of changing the service to accept incorrect messages from the client.

To control the namespaces of your elements you need to use the targetNamespace values on the JAX-WS annotations of your web service and client.

Here is an example to see the difference in code and message format when you change the target namespaces. I'll use a basic WSDL for this:

<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions 
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
xmlns:tns="http://tempuri.org" 
xmlns:xs="http://www.w3.org/2001/XMLSchema" 
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
targetNamespace="http://tempuri.org" 
name="CalculatorWS">
  <wsdl:types>
    <xs:schema targetNamespace="http://tempuri.org">
      <xs:element name="add" type="tns:add" />
      <xs:element name="addInput" type="tns:addInput" />
      <xs:element name="addResponse" type="tns:addResponse" />
      <xs:element name="addOutput" type="tns:addOutput" />
      <xs:complexType name="add">
        <xs:sequence>
          <xs:element name="addInput" type="tns:addInput" />
        </xs:sequence>
      </xs:complexType>
      <xs:complexType name="addInput">
        <xs:sequence>
          <xs:element name="a" type="xs:int" />
          <xs:element name="b" type="xs:int" />
        </xs:sequence>
      </xs:complexType>
      <xs:complexType name="addResponse">
        <xs:sequence>
          <xs:element name="addOutput" type="tns:addOutput" />
        </xs:sequence>
      </xs:complexType>
      <xs:complexType name="addOutput">
        <xs:sequence>
          <xs:element name="result" type="xs:int" />
        </xs:sequence>
      </xs:complexType>
    </xs:schema>
  </wsdl:types>
  <wsdl:message name="add">
    <wsdl:part name="parameters" element="tns:add" />
  </wsdl:message>
  <wsdl:message name="addResponse">
    <wsdl:part name="parameters" element="tns:addResponse" />
  </wsdl:message>
  <wsdl:portType name="CalculatorWS">
    <wsdl:operation name="add">
      <wsdl:input message="tns:add" />
      <wsdl:output message="tns:addResponse" />
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="CalculatorWSPortBinding" type="tns:CalculatorWS">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" />
    <wsdl:operation name="add">
      <soap:operation soapAction="http://tempuri.org/add" />
      <wsdl:input>
        <soap:body use="literal" />
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal" />
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="CalculatorWSService">
    <wsdl:port name="CalculatorWSPort" binding="tns:CalculatorWSPortBinding">
      <soap:address location="http://localhost:8080/WebServices/CalculatorWS" />
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

This defines messages like:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
        xmlns:tem="http://tempuri.org">
   <soapenv:Body>
      <tem:add>
         <addInput>
            <a>?</a>
            <b>?</b>
         </addInput>
      </tem:add>
   </soapenv:Body>
</soapenv:Envelope>

and:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
       xmlns:tem="http://tempuri.org">
   <soapenv:Body>
      <tem:addResponse>
         <addOutput>
            <result>?</result>
         </addOutput>
      </tem:addResponse>
   </soapenv:Body>
</soapenv:Envelope>

See the namespace prefix on the wrappers? That's because the elements are declared in the http://tempuri.org namespace while the others are not and are not in a namespace.

You can even remove all elements from the namespaces. Strip the target namespace from the WSDL and get it to look like this:

<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions 
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
xmlns:xs="http://www.w3.org/2001/XMLSchema" 
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
name="CalculatorWS">
  <wsdl:types>
    <xs:schema>
      <xs:element name="add" type="add" />
      <xs:element name="addInput" type="addInput" />
      <xs:element name="addResponse" type="addResponse" />
      <xs:element name="addOutput" type="addOutput" />
      <xs:complexType name="add">
        <xs:sequence>
          <xs:element name="addInput" type="addInput" />
        </xs:sequence>
      </xs:complexType>
      <xs:complexType name="addInput">
        <xs:sequence>
          <xs:element name="a" type="xs:int" />
          <xs:element name="b" type="xs:int" />
        </xs:sequence>
      </xs:complexType>
      <xs:complexType name="addResponse">
        <xs:sequence>
          <xs:element name="addOutput" type="addOutput" />
        </xs:sequence>
      </xs:complexType>
      <xs:complexType name="addOutput">
        <xs:sequence>
          <xs:element name="result" type="xs:int" />
        </xs:sequence>
      </xs:complexType>
    </xs:schema>
  </wsdl:types>
  <wsdl:message name="add">
    <wsdl:part name="parameters" element="add" />
  </wsdl:message>
  <wsdl:message name="addResponse">
    <wsdl:part name="parameters" element="addResponse" />
  </wsdl:message>
  <wsdl:portType name="CalculatorWS">
    <wsdl:operation name="add">
      <wsdl:input message="add" />
      <wsdl:output message="addResponse" />
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="CalculatorWSPortBinding" type="CalculatorWS">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" />
    <wsdl:operation name="add">
      <soap:operation soapAction="http://tempuri.org/add" />
      <wsdl:input>
        <soap:body use="literal" />
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal" />
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="CalculatorWSService">
    <wsdl:port name="CalculatorWSPort" binding="CalculatorWSPortBinding">
      <soap:address location="http://localhost:8080/WebServices/CalculatorWS" />
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

This new WSDL will correspond to messages like:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Body>
      <add>
         <addInput>
            <a>?</a>
            <b>?</b>
         </addInput>
      </add>
   </soapenv:Body>
</soapenv:Envelope>

and:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Body>
      <addResponse>
         <addOutput>
            <result>?</result>
         </addOutput>
      </addResponse>
   </soapenv:Body>
</soapenv:Envelope>

No prefix in this case.

Now use wsimport.exe on both WSDLs and you will see the target namespaces I was talking about at the beginning, namely a change from this:

@WebService(name = "CalculatorWS", targetNamespace = "http://tempuri.org")
public interface CalculatorWS {
    @WebMethod(action = "http://tempuri.org/add")
    @WebResult(name = "addOutput", targetNamespace = "")
    @RequestWrapper(localName = "add", targetNamespace = "http://tempuri.org", className = "your.pack.age.Add")
    @ResponseWrapper(localName = "addResponse", targetNamespace = "http://tempuri.org", className = "your.pack.age.AddResponse")
    public AddOutput add(
        @WebParam(name = "addInput", targetNamespace = "")
        AddInput addInput);
}

to this:

@WebService(name = "CalculatorWS", targetNamespace = "")
public interface CalculatorWS {
    @WebMethod(action = "http://tempuri.org/add")
    @WebResult(name = "addOutput", targetNamespace = "")
    @RequestWrapper(localName = "add", targetNamespace = "", className = "your.pack.age.Add")
    @ResponseWrapper(localName = "addResponse", targetNamespace = "", className = "your.pack.age.AddResponse")
    public AddOutput add(
        @WebParam(name = "addInput", targetNamespace = "")
        AddInput addInput);
}

Control the targetNamespace and you will control how the message looks.

Share:
28,205
user1642997
Author by

user1642997

Updated on August 05, 2022

Comments

  • user1642997
    user1642997 almost 2 years

    My web service is not able to process my client's requests when client is calling the web service without passing prefix in the SOAP Body as follows:

    <soap:Body> 
     <GetPatientResultsRequest xmlns="http://urlA"> 
      <PatientIdentification> 
          <PersonCivilRegistrationIdentifier xmlns="http://UrlB"/> 
      </PatientIdentification> 
      <Period> 
        <From>2012-05-26</From> 
         <To>2012-06-26</To> 
       </Period> 
     </GetPatientResultsRequest> 
    </soap:Body>
    

    The error is that the Java object corresponding to GetPatientResultsRequest and others are null.

    It seems like when there is no prefix in the Body, the deserialization is not happening properly. My web service is able to respond only when the SOAP Body has a prefix like

    <soap:Body> 
     <m:GetPatientResultsRequest xmlns:m="http://urlA">
      <PatientIdentification> 
          <PersonCivilRegistrationIdentifier xmlns="http://UrlB"/> 
      </PatientIdentification> 
      <Period> 
        <From>2012-05-26</From> 
         <To>2012-06-26</To> 
       </Period> 
     </m:GetPatientResultsRequest> 
    </soap:Body>
    

    Can anyone let me know what to do so that my web service can take SOAP requests of all kinds (i.e. with and without prefix in Body)?

    I am using JAX-WS (SOAP 1.1)

    • Cris
      Cris over 11 years
      what client you use ? jaxws ?
    • John Saunders
      John Saunders over 10 years
      Your two examples are different. In the first case, then namespace is on the GetPatientResultsRequest and the PatientIdentification, Period, From and To elements. In the second example, it's only on the GetPatientResultsRequest element.
    • Haresh Godhani
      Haresh Godhani over 9 years
      I am facing the same problem. Please tell me if you were able to solve your this issue...