Removing XML declaration in WS request

So, I was there: two days after the web services owner tell me that I had to consume their services without the XML declaration in the SOAP request, I didn’t know how to do this yet.

I’ve no idea how many articles and documentations I read, neither about how many attempts I made. Nothing seemed to change that damned that was sent automatically in the top of my SOAP request.

At that time, I was working in a project using the default implementation for web services in Java, JAX-WS. I figured out a solution for my case using some parts of Apache CXF and in this post I intend to show you detailed examples about how to do this.

Publishing sample web service

Firstly, we must to develop a simple web service and publish it so we can test the WSDL. To do this, let’s begin creating a default Maven project called ws-soap-publisher (you can delete all the dependencies and classes automatically generated by Maven).

mvn archetype:generate
  -DarchetypeArtifactId=maven-archetype-quickstart
  -DinteractiveMode=false
  -DgroupId=com.brunozambiazi
  -DartifactId=ws-soap-publisher
  -Dversion=1.0.0
  -Dpackage=com.brunozambiazi.ws.publisher

Open pom.xml and add the JAX-WS dependency:

<dependencies>
  <dependency>
    <groupId>com.sun.xml.ws</groupId>
    <artifactId>jaxws-rt</artifactId>
    <version>2.2.10</version>
  </dependency>
</dependencies>

Now, let’s create a simple web service class with just one service method to print a message:

package com.brunozambiazi.ws.publisher;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;

@WebService
public class HelloWebService {

    @WebMethod
    public void print(@WebParam String something) {
        System.out.format("Printing '%s'", something);
    }

}

We also have to create a simple class to publish the web service on port 8080. After creating the class, just run it.

package com.brunozambiazi.ws.publisher;

import javax.xml.ws.Endpoint;

public class Publisher {

    public static void main(String[] args) {
        System.setProperty("com.sun.xml.ws.transport.http.client.HttpTransportPipe.dump", "true");
        System.setProperty("com.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.dump", "true");
        System.setProperty("com.sun.xml.ws.transport.http.HttpAdapter.dump", "true");
        System.setProperty("com.sun.xml.internal.ws.transport.http.HttpAdapter.dump", "true");

        System.out.println("Publishing service...");
        Endpoint.publish("http://localhost:8080/helloWebService", new HelloWebService());
    }

}

Notice that the first four lines of code in the main method, are just some properties being enabled. This properties are necessary to log the HTTP transport layer, so we can see all the data received as request and sent as response of the web service.

By now, open the browser and try to access the address http://localhost:8080/helloWebService?wsdl. If everything is ok, you will see the contract generated for who wants to consume your web service.

If you want, you can test this web service using a client like SoapUI.

Consuming the web service

Let’s proceed creating a project called ws-soap-consumer to consume and test the web service (again, you can delete all the dependencies and Maven auto generated classes).

mvn archetype:generate
  -DarchetypeArtifactId=maven-archetype-quickstart
  -DinteractiveMode=false
  -DgroupId=com.brunozambiazi
  -DartifactId=ws-soap-consumer
  -Dversion=1.0.0
  -Dpackage=com.brunozambiazi.ws.consumer

Now, edit pom.xml to configure the JAX-WS Maven Plugin. This plugin will generate automatically all the necessary stubs to consume the web service.

<build>
  <plugins>
    <plugin>
      <groupId>org.jvnet.jax-ws-commons</groupId>
      <artifactId>jaxws-maven-plugin</artifactId>
      <version>2.3</version>
      <executions>
        <execution>
          <goals>
            <goal>wsimport</goal>
          </goals>
          <configuration>
            <vmArgs>
              <vmArg>-Djavax.xml.accessExternalSchema=all</vmArg>
            </vmArgs>
            <wsdlUrls>
              <wsdlUrl>http://localhost:8080/helloWebService?wsdl</wsdlUrl>
            </wsdlUrls>
            <sourceDestDir>src/main/java</sourceDestDir>
          </configuration>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

Execute the project with Maven, running with the package phase. You’ll notice that some classes were generated inside a new package with the same name as the main package of the other project. At that time, your project must seem like this:

ws-soap-consumer-project

To finish this part, let’s create the class to consume the web service:

package com.brunozambiazi.ws.consumer;

import com.brunozambiazi.ws.publisher.HelloWebService;
import com.brunozambiazi.ws.publisher.HelloWebServiceService;

public class Consumer {

    public static void main(String[] args) {
        HelloWebServiceService service = new HelloWebServiceService();
        HelloWebService port = service.getHelloWebServicePort();
        port.print("First consumer!");
    }

}

The problem

Ok, we have all the necessary stuffs to see the “problem” happenning. (At least for me this was a problem…)

First of all, run the publisher class. You must see the output message “Publishing service…”.

Now, run the consumer class. The complete output must be something like this:

---[HTTP request]---
Accept: text/xml, multipart/related
Connection: keep-alive
Host: localhost:8080
User-agent: JAX-WS RI 2.2.10 svn-revision#919b322c92f13ad085a933e8dd6dd35d4947364b
Content-type: text/xml; charset=utf-8
Soapaction: "http://publisher.ws.brunozambiazi.com/HelloWebService/printRequest"
Content-length: 234
<?xml version='1.0' encoding='UTF-8'?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><ns2:print xmlns:ns2="http://publisher.ws.brunozambiazi.com/"><arg0>First consumer!</arg0></ns2:print></S:Body></S:Envelope>--------------------

Printing 'First consumer!'---[HTTP response 200]---
Date: Sat, 19 Dec 2015 01:03:29 GMT
Transfer-encoding: chunked
Content-type: text/xml; charset=utf-8
<?xml version="1.0" ?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><ns2:printResponse xmlns:ns2="http://publisher.ws.brunozambiazi.com/"></ns2:printResponse></S:Body></S:Envelope>--------------------

Do you see the  in line 9? This is the damned!

The solution

After numerous attemps and research, I solved my problem just replacing the JAX-WS dependency by two modules of Apache CXF.

So, open the consumer’s project pom.xml and let the dependencies tag this way:

<dependencies>
  <dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-transports-http</artifactId>
    <version>3.1.4</version>
  </dependency>
  <dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-frontend-jaxws</artifactId>
    <version>3.1.4</version>
  </dependency>
</dependencies>

Now, try again. Run the consumer class and take a look at the output:

---[HTTP request]---
Accept: */*
Connection: keep-alive
Host: localhost:8080
Pragma: no-cache
User-agent: Apache CXF 3.1.4
Content-type: text/xml; charset=UTF-8
Soapaction: ''
Content-length: 211
Cache-control: no-cache
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:print xmlns:ns2="http://publisher.ws.brunozambiazi.com/"><arg0>First consumer!</arg0></ns2:print></soap:Body></soap:Envelope>--------------------

Printing 'First consumer!'---[HTTP response 200]---
Date: Sat, 19 Dec 2015 01:18:57 GMT
Transfer-encoding: chunked
Content-type: text/xml; charset=utf-8
<?xml version="1.0" ?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><ns2:printResponse xmlns:ns2="http://publisher.ws.brunozambiazi.com/"></ns2:printResponse></S:Body></S:Envelope>--------------------

Pay attention in line 11, where the request SOAP envelope is shown. Can you see the XML declaration? Of course not, because it isn’t there anymore! By default, Apache CXF doesn’t specify this – and this is exactly what I was looking for.


I know this is a specific and maybe unlikely situation, but it was very hard to find out a solution and so I decided to share my (maybe unpleasant) experience with that.

You can get the source code from this post on my GitHub account, here and here.

See you soon.

Advertisements

Let me your thoughts

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s