Thursday, January 31, 2008


Starting from scratch to write a web service, getting a WAR built, deployed into JBoss or your favorite container can be a pain. I always start with an existing ant script and project, remove all the existing artifacts, then start fresh. This means, typically, an hour or so of deleting unneeded jars/classes/relics, search-n-replacing, fixing built script to remove any references to the old project-specific crud, deploying to my container to test a simple hello-world-ish app.

I hate doing this "setup" type work. It's boring and lame. .NET makes it really easy to startup a new project, so why do I hate doing it in Java?

So, what options are there for Java? One I have recently run across is Enunciate from our XFire friends at CodeHaus.

Enunciate appears to solve a nice little java pain point -- "How can I rapidly deploy a webservice without bothering with all the infrastructure crud?"

With a few simple JSR 181 annotations, and using enunciate, you can quickly wrap up a complete, deployable WAR which contains a WS-I Basic Profile compliant web service, nice browsable service documentation, client code in the form of a JAR, WSDL, etc.

If it sounds like a lot of effort, don't be fooled. I loosely followed the enunciate Quick Start and had my own simple web service up and running within a few minutes. This included setting up the eclipse project, downloading and unpacking enunciate, creating the ant build script, deploying to JBoss, and playing with the created application.

Let's go through a quick example on setting up enunciate, building a sample project, and deploying it to JBoss.

Enunciate is very module. In fact, all of the default functionality is provided via a set of modules that come with enunciate out of the box. If there is a deployable artifact that you want and there isn't a module for your desired functionality, then you are free to create your own module and donate it back to the project.

Getting Set Up
I'll assume you already have a JDK, IDE, and a container installed. Download enunciate from The latest at the time of this post is 1.6, release on January 8, 2008. The download is only 9.2 megs.

Extract the archive to some location. I extracted it to $HOME/bin.

If you want to run enunciate from cmd line versus ant script, then add enunciate/bin to your path. I'm going to walk through setting up enunciate as an ant task.
Example Project
My sample project doesn't vary much from the enunciate Quick Start. I just like to try things myself in hopes that I hit something new. The example project I quickly thought of is a music service which will have admin and search capabilities for artists, albums, and songs. It is pretty simple, but just to illustrate the simplicity of enunciate and how it can handle some complexities of a "real-world" example.

My example will have artists who can have zero-or-more albums which can have zero-or-more songs. The service will allow adding relationships and searching.

First, I created the project structure and created the simple directory structure:
|----build.xml (I'll be using ant)
api -- contains interfaces and exceptions which define the exposed service
model -- contains business models and relationships
impl -- implementation classes for the interfaces

Next, I defined the interface for the service. The service will be simple and define the following operations. Note the @WebService annotation (from jsr-181)

import javax.jws.WebService;


public interface MusicServiceInterface {
public Artist addArtist(Artist artist) throws AlreadyExistsException;
public Album addAlbum(Artist artist, Album album) throws AlreadyExistsException;
public Song addSong(Album album, Song song) throws AlreadyExistsException;
public Song[] searchSongs(String someSearchText);

Now create skeletons for Album, Artist, and Song as well as AlreadyExistsException, just to get things to compile. For this example, I'm NOT interested in implementing the actual functionality of a music search service; instead, I am only interested in how we expose a service quickly using enunciate.

Next up is to define the implementation class as follows. Note the reference to the implementation class in the @WebService annotation.

import javax.jws.WebService;


@WebService (
endpointInterface = ""
public class MusicServiceImpl implements MusicServiceInterface {

public Album addAlbum(Artist artist, Album album)
throws AlreadyExistsException {
// TODO Auto-generated method stub
return null;

public Artist addArtist(Artist artist) throws AlreadyExistsException {
// TODO Auto-generated method stub
return null;

public Song addSong(Album album, Song song) throws AlreadyExistsException {
// TODO Auto-generated method stub
return null;

public Song[] searchSongs(String someSearchText) {
// TODO Auto-generated method stub
return null;


Now I have a compilable, but not-yet-functional application. Let's go ahead and see what happens when we use enunciate to create the WAR artifact and deploy it to JBoss.

I want to use ant for this example, so here's a sample build.xml file that you can modify to meet your needs:

    <project name="music-enunciate-example" default="package">

<target name="init">
<property name="enunciate.home" value="/home/dbreese/bin/enunciate-1.6" />
<property name="jdk.home" value="/opt/java/" />

<path id="enunciate.classpath">
<fileset dir="${enunciate.home}/lib">
<include name="**/*.jar" />
<fileset dir="${enunciate.home}">
<include name="enunciate-full-*.jar" />
<fileset dir="${jdk.home}/lib">
<include name="tools.jar"/>

<taskdef name="enunciate" classname="org.codehaus.enunciate.main.EnunciateTask">
<classpath refid="enunciate.classpath" />


<target name="clean">
<delete dir="dist"/>

<target name="package" depends="clean,init">
<mkdir dir="dist"/>
<enunciate basedir="src">
<include name="**/*.java" />
<classpath refid="enunciate.classpath" />
<export artifactId="spring.war.file" destination="dist/${}.war" />

NOTE: I ran into an issue where it was complaining about "java.lang.NoClassDefFoundError: com/sun/mirror/apt/AnnotationProcessorFactory". To fix, I had to add jdk.home/lib/tools.jar to my classpath. I literally spent 50% of my time on this sample project trying to fix this stupid little error!

Notice the "artifactId" which is "spring.war.file". This indicates that a fully functional WAR FILE will be created. Another possible value is "spring.war.dir" which is an exploded WAR directory.

Enunciate can also produce FLEX-compatible artifacts.

Build the project by running "ant package".

Once it is successfully built, deploy dist/music-enunciate-example.war to your container. Since I'm using a default instance of jboss, I just copy it into $JBOSS_HOME/server/default/deploy and JBoss will deploy it.

Now, open your browser and hit "http://localhost:8080/music-enunciate-example". You should see the following sample page:

The web page has all the complete documentation, wsdl, and even includes a downloadable client.

Documentation is generated directly from javadocs, so as long as you follow good javadoc practices, the html documentation generated by enunciate will be great.

Customization and Modules

You can provide a configuration file that allows you to personalize URLs, namespaces, package names, documentation pages, etc. The configuration file can be provided in the enunciate ant task with the configFile attribute, or the "-f" cmd line option. It appears enunciate also makes use of a "" class for annotations which will drive namespaces, documentation, etc.

Enunciate can be extended with modules. The core functionality of enunciate is implemented with modules. For example, the xfire-client module is responsible for generating the downloadable xfire client. The enunciate configuration file has a section which is used to configure each module. Check out this link for information on the core modules that come with enunciate.

Enunciate can also generate restful services for you. This is accomplished using the "rest" module. (See Constraints enunciate places on exposing REST models)

I want to dive more into how enunciate can help with REST APIs in a future article.

Misc Questions
  1. WTF is "artifactId" in the enunciate ant target? Here's a good link which articulates what is available.

Some things I still want to investigate:
  1. How easily is it incorporated into existing projects?
    It seems that you can easily incorporate enunciate into existing projects, but you'd then have multiple ways of exposing your web services which adds project complexity.
  2. Can it handle WSDL/contract-first development?
    Enunciate is more aimed at code-first approach. Still trying to get mind around it and see if WSDL-First is possible.
  3. How does it incorporate into ant/maven? Easy. Plus, see above for a working ant script using the enunciate task.


Ryan said...

Hey Dustin. I enjoyed your post; it's nice to be able to walk through another user's perspective. Sorry about the NoClassDefFoundError--I've updated the docs for the Ant entry point to show that you really need to include $JAVA_HOME/lib/tools.jar.

By the way, "artifactId" is simply the id that Enunciate assigns to that artifact (internally). Enunciate produces a ton of "artifacts" throughout its build process, and if you ever want to tell Enunciate to put those artifacts somewhere else, you have to be able to tell Enunciate which artifact you want to copy. You do that with the artifact id. See the docs for the nested "export" element for the Ant task, for example.

Anonymous said...

My Gosh..

Finally an example without any of that maven garbage. Thanks man!

Anonymous said...

Two things:
I think in your directory structure diagram the build.xml is placed too deep in the tree. I normally see it in the same dir as src.
Also. Using your instructions, I keep getting:
org.codehaus.enunciate.EnunciateException: You must specify a "rpcModuleName" for the GWT module.
at org.codehaus.enunciate.modules.gwt.GWTDeploymentModule.init(

I don't have nor do I want anything to do with GWT.. How can I get rid of this?

Anonymous said...

And then it complained about multiple jax-ws providers, and i had to figure out how to make an enunciate.xml file that disables them..

So far it's looking like enunciate is anything but an "it just works" framework

Anonymous said...

And then it complains about missing some random csharp file in /tmp/somereallylongnumber/

Anonymous said...

Sorry, I wasn't using your same version of enunciate..
I've tried to get the newer verison to work on about three different machines and it never worked.. Just checkout out this version that you're using, and it worked fine..

Hey Enunciate, can you fix your newer version to "just work"?