Java web service method receiving null argument from C# client

Mark Bouchard picture Mark Bouchard · Sep 15, 2011 · Viewed 9.3k times · Source

I'm working on a Java 6 application server which has a web service for receiving a SOAP messages containing an HL7 message. The Java application runs on Glassfish 3.1. The client is a third-party developed C# application (which runs on the Microsoft .net 4.0 framework) and it is sending these SOAP messages to the Java server.

My initial issue was that the client was unable to parse the WSDL generated by the server. I have since resolved that by implementing my own custom WSDL and tuning it accordingly. This allowed the client to parse the WSDL and send SOAP messages to my Java server application.

However, each time a message is received on the server side, the parameter (named "putXML") is receiving a null value.

The Glassfish server log shows the following when a message is received:

Received WS-I BP non-conformant Unquoted SoapAction HTTP header: http://MyProject.MyPackage/putHL7Data
Received Message: null

Here is the custom WSDL that I created and associated with my SOAP web service:

<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions
      targetNamespace="http://MyProject.MyPackage/"
      xmlns="http://schemas.xmlsoap.org/wsdl/"
      xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" 
      xmlns:s="http://www.w3.org/2001/XMLSchema"
      xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
      xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" 
      xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 
      xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
      xmlns:tns="http://MyProject.MyPackage/" 
      xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" 
      xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
      xmlns:wsp="http://www.w3.org/ns/ws-policy" 
      xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
      xmlns:xsd="http://www.w3.org/2001/XMLSchema">   
   <wsdl:types>
      <s:schema elementFormDefault="qualified" targetNamespace="http://MyProject.MyPackage/">
         <s:element name="putHL7Data">
            <s:complexType>
               <s:sequence>
                  <s:element name="putXML" type="s:string" minOccurs="0" maxOccurs="1"/>
               </s:sequence>
            </s:complexType>
         </s:element>
         <s:element name="putHL7DataResponse">
            <s:complexType>
               <s:sequence>
                  <s:element name="return" type="s:string" minOccurs="0" maxOccurs="1"/>
               </s:sequence>
            </s:complexType>
         </s:element>
      </s:schema>
   </wsdl:types>
   <wsdl:message name="putHL7DataSoapIn">
      <wsdl:part name="parameters" element="tns:putHL7Data"/>
   </wsdl:message>
   <wsdl:message name="putHL7DataSoapOut">
      <wsdl:part name="parameters" element="tns:putHL7DataResponse"/>
   </wsdl:message>
   <wsdl:portType name="MyHandlerSoap">
      <wsdl:operation name="putHL7Data">
         <wsdl:input message="tns:putHL7DataSoapIn"/>
         <wsdl:output message="tns:putHL7DataSoapOut"/>
      </wsdl:operation>
   </wsdl:portType>
   <wsdl:binding name="MyHandlerSoap" type="tns:MyHandlerSoap">
      <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
      <wsdl:operation name="putHL7Data">
         <wsdl:input>
            <soap:body use="literal"/>
         </wsdl:input>
         <wsdl:output>
            <soap:body use="literal"/>
         </wsdl:output>
      </wsdl:operation>
   </wsdl:binding>
   <wsdl:service name="MyHandler">
      <wsdl:port name="MyHandlerPort" binding="tns:MyHandlerSoap">
         <soap:address location="REPLACE_WITH_ACTUAL_URL"/>
      </wsdl:port>
   </wsdl:service>
</wsdl:definitions>

And here is the Java web service:

@WebService(serviceName = "MyHandler", wsdlLocation = "WEB-INF/wsdl/MyHandler.wsdl")
public class MyHandler {
   @WebMethod(operationName = "putHL7Data")
   public String putHL7Data(@WebParam(name = "putXML") String xml) {
      // Handle message
   }
}

Is there anything I am doing wrong?

What can I do to fix the Java web service so that it properly receives a non-null value?

Is this an issue with the client? If so, would I need to create some sort of interceptor?

Update

Today I tried creating a quick C# client which uses my Java SOAP web service. Below is the code:

namespace TestSoap
{
    class Program
    {
        static void Main(string[] args)
        {
            ServiceReference1.MyHandlerSoapClient ws = new ServiceReference1.MyHandlerSoapClient();
            string result = ws.putHL7Data("Test");    
            Console.WriteLine("Response: " + result);
            Console.ReadLine();
        }
    }
}

When I run this client, I receive the same null value in the parameter when I was expecting to see the Test string. Also, I'm expecting result to contain a response string but it too is returning a null value.

Remember, I cannot modify the third-party C# client application. Is there anything I can do on the Java end?

Update 2

I recently added a handler chain class which is capturing and logging the raw SOAP messages. The message being sent by the client looks like this:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soap:Header/>
  <soap:Body>
    <putHL7Data xmlns="http://MyProject.MyPackage/">
      <putXML>... Encoded XML Here ...</putXML>
    </putHL7Data>
  </soap:Body>
</soap:Envelope>

Answer

Mark Bouchard picture Mark Bouchard · Sep 19, 2011

After getting pointed in the right direction by @dlawrence, I was able to solve my issue. As I mentioned in the question, I still needed to use a custom built wsdl. I only needed to make a few changes to the wsdl and the Java code to solve the issue.

Here's a diff representing my changes to the wsdl:

--- /tmp/a  2011-09-19 15:05:21.132065003 -0400
+++ /tmp/b  2011-09-19 14:41:28.302064999 -0400
@@ -15,11 +15,11 @@
       xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
       xmlns:xsd="http://www.w3.org/2001/XMLSchema">   
    <wsdl:types>
-      <s:schema elementFormDefault="qualified" targetNamespace="http://MyProject.MyPackage/">
+      <s:schema targetNamespace="http://MyProject.MyPackage/">        
          <s:element name="putHL7Data">
             <s:complexType>
                <s:sequence>
-                  <s:element name="putXML" type="s:string" minOccurs="0" maxOccurs="1"/>
+                  <s:element name="putXML" type="s:string" form="qualified" minOccurs="0" maxOccurs="1"/>
                </s:sequence>
             </s:complexType>
          </s:element>
@@ -47,6 +47,6 @@
    <wsdl:binding name="MyHandlerSoap" type="tns:MyHandlerSoap">
       <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
       <wsdl:operation name="putHL7Data">
-         <soap:operation soapAction="" style="document"/>
+         <soap:operation soapAction="http://MyProject.MyPackage/putHL7Data" style="document"/>
          <wsdl:input>
             <soap:body use="literal"/>
          </wsdl:input>

Basically this was a three part fix...
1). I needed to remove the elementFormDefault="qualified" attribute from the <s:schema> tag.
2). Then I had to add the attribute form="qualified" on my <s:element name="putXML" ...> tag.
3). Finally, I needed to make sure I had the attribute soapAction="http://MyProject.MyPackage/putHL7Data" on my <soap:operation> tag.

Here's a diff representing my changes to the Java web method:

--- /tmp/a  2011-09-19 14:57:49.582065002 -0400
+++ /tmp/b  2011-09-19 15:00:06.942065007 -0400
@@ -1,7 +1,7 @@
 @WebService(serviceName = "MyHandler", wsdlLocation = "WEB-INF/wsdl/MyHandler.wsdl")
 public class MyHandler {
    @WebMethod(operationName = "putHL7Data")
-   public String putHL7Data(@WebParam(name = "putXML") String xml) {
+   public String putHL7Data(@WebParam(name = "putXML", targetNamespace="http://MyProject.MyPackage/") String xml) {
       // Handle message
    }
 }

As you can see, all I had to do was add the targetNamespace attribute to my @WebParam.