Introduction
A couple of weeks ago one of our clients asked me to prepare some documentation on the CQ/JCR RESTful services I had created for them.
I had previously came across this post on TSS about the latest release of enunciate. Unfortunately, I quickly forgot. Then Bill reminded me about it a couple days ago. He is working on a REST/Flex project and he too came across it. Its all coming together now.
enunciate
While enunciate can do a variety of things, I was only interested in the generated JAX-RS/JAXB documentation (HTML). My personal opinion is that the generated documentation is not only useful but also well designed. As a colleague commented, it is pretty. Here is a screenshot of the documentation for JC-Rest.

To actually add it to JC-Rest was quite easy. A testament to the enunciate developers. I happen to use Maven to build JC-Rest so all I had to do was add the enunciate plugin and its dependencies.
pom.xml
<project>
...
<dependencies>
<dependency>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>enunciate-rt</artifactId>
<version>1.8</version>
<exclusions>
<exclusion>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>enunciate-amf-rt</artifactId>
</exclusion>
<exclusion>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>enunciate-gwt-rt</artifactId>
</exclusion>
<exclusion>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>enunciate-jersey-rt</artifactId>
</exclusion>
<exclusion>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>enunciate-rest-rt</artifactId>
</exclusion>
<exclusion>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>enunciate-spring-app-rt</artifactId>
</exclusion>
<exclusion>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>enunciate-xfire-client-rt</artifactId>
</exclusion>
<exclusion>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>enunciate-xfire-rt</artifactId>
</exclusion>
<exclusion>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
</exclusion>
<exclusion>
<groupId>javax.xml.ws</groupId>
<artifactId>jaxws-api</artifactId>
</exclusion>
<exclusion>
<groupId>xfire</groupId>
<artifactId>xfire-jsr181-api</artifactId>
</exclusion>
</exclusions>
</dependency>
...
</dependencies>
<build>
<finalName>jc-rest</finalName>
<plugins>
<plugin>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>maven-enunciate-plugin</artifactId>
<configuration>
<configFile>enunciate.xml</configFile>
</configuration>
<executions>
<execution>
<goals>
<goal>assemble</goal>
</goals>
</execution>
</executions>
</plugin>
...
</plugins>
</build>
</project>
I added the exclusions to avoid littering my WAR with unnecessary JARs. The exclusions are certainly not required.
Finally, we just add the enunciate configuration file.
enunciate.xml
<?xml version="1.0"?>
<enunciate xsi:noNamespaceSchemaLocation=
"http://enunciate.codehaus.org/schemas/enunciate-1.8.xsd">
<namespaces>
<namespace id="jc-rest" uri="http://www.jc-rest.org"/>
</namespaces>
<api-classes>
<exclude pattern="org.jcrest.listener.*"/>
</api-classes>
<modules>
<docs docsDir="docs" title="JC-REST"/>
</modules>
</enunciate>
It appears that enunciate will assume that all of your non JAX-RS annotated classes are JAXB types. As a result you should exclude utility classes and what not as I did. Also, enunciate will throw an exception if it comes a cross a class whose properties are precomplied classes. In the event that happens, you’ll have to import the classes via the ‘api-import’ element in the configuration. See this Wiki page for more information.
Since I only wanted the documentation I only added the docs module. The docsDir property specifies the directory in the WAR where the documentation assets should go. The title attribute is the the text you see in the header of the HTML pages.
JAX-RS, JAXB, namespaces, & JSON
Because I am a perfectionist, this is where it gets a little tricky. Enunciate will generate a schema based on the classes it found. This is going to be an invalid schema because no namespace has been defined. That doesn’t break the documentation. It just annoys me. Yes, we added a namespace element in the enunciate configuration file but that is irrelevant until we configure that namespace in JAXB. I added the namespace via JAXB annotations in newly created package-info.java classes in each of the bean packages.
package-info.java
@XmlSchema (namespace = "http://www.jc-rest.org",
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package org.jcrest.bean;
import javax.xml.bind.annotation.XmlSchema;
One important item to note is the presence of the elementFormDefault property. If you don’t add this, JAXB will generate a random prefix and use it in the marshalled XML.
So now enunciate is generating a valid schema, the documentation looks great, and our XML response is as it should be. The problem is if we request a JSON response we will get an ‘Invalid JSON namespace’ error from Jettison. To fix this we have to register the namespace with the CXF JAX-RS JSONProvider. This, of course, is done in our Spring configuration.
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxrs="http://cxf.apache.org/jaxrs"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-2.0.xsd
http://cxf.apache.org/jaxrs
http://cxf.apache.org/schemas/jaxrs.xsd">
...
<util:map id="jsonNamespaceMap" map-class="java.util.Hashtable">
<entry key="http://www.jc-rest.org" value=""/>
</util:map>
<jaxrs:server id="contentServer" address="/">
...
<jaxrs:providers>
...
<bean class="org.apache.cxf.jaxrs.provider.JSONProvider">
<property name="namespaceMap" ref="jsonNamespaceMap"/>
</bean>
</jaxrs:providers>
...
</jaxrs:server>
...
</beans>
Now that Jettison namespace error will disappear. You’ll notice that I set the prefix value to an empty string. That is because I didn’t want a prefix showing up in the JSON response. As a side note, don’t forget to add the Spring util schema/namespace as shown.
Conclusion
That is it. We have enunciate generating our JAX-RS/JAXB documentation, and we have the same XML/JSON responses we always did. Right now the JAX-RS service parameters are listed but the descriptions are missing. The same is true for the XML element/attribute descriptions. However, if I simply fill in the appropriate Javadocs the descriptions will show up. I suppose that is the next thing I’ll work on.
So until next time, good fight, good night.