I have been doing a little bit of work recently on Jersey implementation and one of the precursors to this has been to try to get the WADL that Jersey will generation by default to contain just a little bit more information with regards to the data being transferred. This makes it possible to help the user when generating client code and running testing tools against resources.
To this end I have put together a WADL generator decorator that examines all the JAX-B classes used by the -RS application and generates a bunch of XML Schema files. This is now in 1.9-SNAPSHOT which you can download from the Jersey web site in the normal way. (If you want to use the JResponse part of this you will need a build after the 13th of July)
This feature is not enabled by default in 1.9; but hopefully with some good feedback and a small amount of caching I might convince the Jersey bods to make this the default. For the moment you need to create and register a WsdlGeneratorConfig class to get this to work. So your class might look like this:
package examples; import com.sun.jersey.api.wadl.config.WadlGeneratorConfig; import com.sun.jersey.api.wadl.config.WadlGeneratorDescription; import com.sun.jersey.server.wadl.generators.WadlGeneratorJAXBGrammarGenerator; import java.util.List; public class SchemaGenConfig extends WadlGeneratorConfig { @Override public List<WadlGeneratorDescription> configure() { return generator( WadlGeneratorJAXBGrammarGenerator.class ).descriptions(); } }
You then need to make this part of the initialization of the Jersey servlet, so your web.xml might looks like this:
<?xml version = '1.0' encoding = 'windows-1252'?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <servlet> <servlet-name>jersey</servlet-name> <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class> <init-param> <param-name>com.sun.jersey.config.property.WadlGeneratorConfig</param-name> <param-value>examples.SchemaGenConfig</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>jersey</servlet-name> <url-pattern>/jersey/*</url-pattern> </servlet-mapping> </web-app>
For the purposes of this blog I am just going to show the three basic references to entities that the code supports. So at the moment if will obviously process classes that are directly referenced and either a return value or as the entity parameter on a method. The code also supports the Jersey specific class JResponse, which is a subclass of Response that can have a generic parameter. (Hopefully this oversight will be fixed in JAX-RS 2.0)
package examples; import com.sun.jersey.api.JReponse; import examples.types.IndirectReturn; import examples.types.SimpleParam; import examples.types.SimpleReturn; import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.Produces; @Path("/root") public class RootResource { @GET @Produces("application/simple+xml") public SimpleReturn get() { return new SimpleReturn(); } @GET @Produces("application/indrect+xml") public JResponse<IndirectReturn> getIndirect() { return JResponse.ok(new IndirectReturn() ) .type( "application/indrect+xml" ).build(); } @PUT @Consumes("application/simple+xml") public void put(SimpleParam param) { } }
The type classes are all pretty trivial so I won't show them here. The only important factor is that they have the @XmlRootElement annotation on them. Although not shown here you can also use the JAX-B annotation @XmlSeeAlso on the resource classes to reference other classes that are not directly or indirectly referenced from the resource files. The most common use case for this is when you have a subtype of a class.
So enough of the java code, lets see what the WADL that is generated looks like:
<?xml version="1.0" encoding="UTF-8"?> <application xmlns="http://wadl.dev.java.net/2009/02"> <doc xmlns:jersey="http://jersey.java.net/" jersey:generatedBy="Jersey: 1.9-SNAPSHOT 07/13/2011 11:13 AM"/> <grammars> <include href="application.wadl/xsd0.xsd"> <doc xml:lang="en" title="Generated"/> </include> </grammars> <resources base="http://localhost:7101/JerseySchemaGen-Examples-context-root/jersey/"> <resource path="/root"> <method name="GET" id="get"> <response> <representation xmlns:ns2="urn:example" mediaType="application/simple+xml" element="ns2:simpleReturn"/> </response> </method> <method name="PUT" id="put"> <request> <representation xmlns:ns2="urn:example" mediaType="application/simple+xml" element="ns2:simpleParam"/> </request> </method> <method name="GET" id="getIndirect"> <response> <representation xmlns:ns2="urn:example" mediaType="application/indrect+xml" element="ns2:indirectReturn"/> </response> </method> </resource> </resources> </application>
In this example there is only one schema in the grammar section; but the code supports multiple schemas being generated with references between them. Let look at the schema for this example, note I did say the classes were trivial!
<?xml version="1.0" encoding="UTF-8"?> <xs:schema version="1.0" targetNamespace="urn:example" xmlns:tns="urn:example" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="indirectReturn" type="tns:indirectReturn"/> <xs:element name="simpleParam" type="tns:simpleParam"/> <xs:element name="simpleReturn" type="tns:simpleReturn"/> <xs:complexType name="indirectReturn"> <xs:sequence/> </xs:complexType> <xs:complexType name="simpleReturn"> <xs:sequence/> </xs:complexType> <xs:complexType name="simpleParam"> <xs:sequence/> </xs:complexType> </xs:schema>
There is still some internal work to be done on caching; but the basics are in place. Feedback would be appreciated, particularly in cases where the code doesn't see the referenced classes. Finally thanks to Pavel Bucek for being patient as I learned the ropes.
Update 5th September 2011 This feature has been enabled by default so you no longer have to perform any of the WadlGeneration configuration when working with 1.9 final release of Jersey.