O'Reilly logo

Java SOA Cookbook by Eben Hewitt

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Setting Up a Maven 2 Service and Client Project


You want to create a project to house a web service and its client in Maven 2. You already understand Maven, but you aren’t sure what plug-ins you need, what goals to associate them with, or how to structure it.


Create three projects: one for the service, one for the client, and a parent. Run unit tests in the service and client projects. Also, there are some general dependencies you’ll want to set up to work with Java EE 5, and you’ll need to update the default Java SDK to 1.6.


For the examples in this book that use Java SE 6, you’ll need to update your POM to include the compiler plug-in that uses SE 6, as shown below:


This ensures that the JAX-WS and XML libraries you’ll need will be available.

In general, the easiest way to create web services is to use Maven 2, set up a web project (specify <packaging>war</packaging>), and then create a POJO that has the @WebService annotation on the class. If you stop there, however, your WAR will deploy properly but won’t contain any web services. That’s because by default Maven 2 uses an older DTD for Servlet 2.3 in the web.xml file. To solve this, add the following dependency to your pom.xml:


Then you have to replace the web-app declaration. Look in your project’s src/main/webapp/WEB-INF folder for the web.xml file, and replace the following code:

 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >
  <display-name>My Service</display-name>

with the Servlet 2.5 version specified here:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 
   <display-name>My Service</display-name>

You also need to set up dependencies for Metro only if you are doing any Metro-specific code (like WS-Addressing on the client, or a stateful web service that relies on Metro’s export mechanism):


Now when you deploy your projects, they’ll know to interpret the annotations and create a service for you.

Overall, the idea is this: you create a parent so that you have a place to build that creates the entire world for you with a single click. It builds the service first, then deploys it, and then builds the client, using the freshly deployed WSDL.

With your JUnit tests, make sure that you test in both the service and client projects. Hopefully, this will seem obvious. But the confusion here can stem from our tendency to think that the web service project must be tested as a web service because that is what’s being built. But that would require testing after deployment, which goes against the grain of how Maven works. It’s easy enough to get the results you want by following Maven conventions.

Basically, because the deploy phase happens after the test phase, your service project build should test the code directly, as regular Java code, not the code deployed as a web service with a WSDL. To do so, you can make use of mock objects. The Jakarta Commons project is helpful here. It allows you to mock JNDI calls and make connections to a database defined as a DataSource in your container. That will make sure that the Java code is thoroughly tested (you can use Cobertura from http://cobertura.sourceforge.net/ to see just how much). The client project will then execute its tests against the live, freshly deployed service.

Creating the service project

The service project is just a regular EAR or WAR project, depending on whether you’re using an EJB or a servlet for your service implementation. The only thing to note is that you want to make the service artifact deploy automatically at build time, so that when the client builds too, it can read the new WSDL and get the new implementation of the service. You do that as you would with any regular WAR or EAR. If you’re using Glassfish, here’s a good plug-in to use:


This plug-in executes during the install phase to deploy your WAR or EAR automatically during your build. This is a nice convenience. The only item of note here is that it’s important to use a property for things like paths that might be specific to a given developer’s box. Here, I’m referencing a property whose value is specified in my own settings.xml file.

Creating the client project

If you are creating a service for public consumption, you may just stop at creating the service itself, and let clients figure out on their own how to use it. But you might want to also create a client JAR that you can make available to users on a Java platform, as a convenience. This is something that Amazon, eBay, Google, and others did in the early days of web services, to make their services easier to work with. They’d distribute a client ZIP file that contained both Java and C# code, allowing developers to get up and running with their services more quickly.

Even if you are developing web services for internal use only, it still may be a good idea to create a client JAR that already contains the generated artifacts off the WSDL so that integrating usage of your service into business applications is not only easier, but also more controlled. For example, if you’re creating the client JAR, you can add features such as WS-Addressing, schema validation, and so on without requiring every developer in your shop to understand all those things, or even to be aware that they’re happening under the hood. This allows you more flexibility. Of course, if you have business applications written in COBOL or C# that need to invoke your service, they can’t use your Java client. You can then either create one for them, or let them do it themselves.


If you’re creating both the service implementation and a convenience client, be certain that you are designing your service in a fully encapsulated manner, and not allowing the client to do any real work. That might sound obvious enough, but it’s an easy trap to fall into when you are getting started and doing services internally—especially because in order to make the learning curve shorter, the designers of the Java web service APIs made everything build on familiar web technologies.

Here’s an easy rule of thumb to make this distinction. If you’re making both a client and the service simultaneously, that’s fine. It’s a common thing to do. But be sure not to have any code in your client JAR that is necessary for the functioning of your solution. It’s only a convenience, nothing more. If there’s code in your client that would make the overall solution fail were it removed, the service is designed wrong, and you need to find a way to move that functionality back into the service.

Your client and service projects need to be versionable independently of one another. For example, you might add multithreading to your client, but that doesn’t mean that anything in your service has changed. You need to be able to redistribute the client to a Maven repository separately, with its own version.

For the client project, use the wsimport plug-in like this:


The JAX-WS plug-in is available at https://jax-ws-commons.dev.java.net/jaxws-maven-plugin/. It allows you to add wsimport and wsgen functionality to your Maven 2 build. The <packageName> is the name of your generated source package.

Creating the parent project

You don’t truly need the parent project, but it does allow you to specify shared dependencies, such as Java SE 6, Log4J, JUnit, or other items that both the client and the service require. The parent can declare these dependencies, and also declare its children as the service and client projects, like this:


The purpose of the parent is so that you can build and deploy the service, then immediately build the client against it to make sure that any changes in your WSDL are compatible with your client, and vice versa.

Another reason is so that you have a single umbrella project that makes a convenient target for integration builds. For example, if you’re using something like Cruise Control (http://cruisecontrol.sourceforge.net/) or Hudson (https://hudson.dev.java.net/) to perform continuous integration, it’s easier to set up that tool to point to a single POM it needs to build.

However, if you’re using a tool like Hudson on its own build server, you will probably need to set up a profile for the build server to use when it specifies WSDL locations, a path to the application server it should deploy to, and so on. Here’s a quick example:

<!-- For shared Continuous Integration Hudson Build. 
     Developers should have their own profile set in profiles.xml, 
     which should be ignored by source repository. -->
     <!-- This property is passed to Maven from within 
          the Hudson build configuration on the build server. -->

Then in the project for this service that you’ve made in your continuous integration (CI) tool, you can specify a system property that controls what machine this project is being built from. Here I’ve used the integrationBuild property that the Hudson project has configured to pass as an argument to the build, so that the properties for it to use (such as the location of the app server to deploy to and the WSDL URL that the client should read) are triggered.

Thanks to Brian Mericle for his work with me on this solution.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required