Generated WADL for a List of Resources
Asked Answered
I

1

6

I am struggling for a couple of days now with the following problem. I searched quite a lot for an answer, here in SO, in jersey mailing lists and the net in general, but weren't able to find answer to this particular question.

Setting up the problem domain...

I am using Jersey 1.16 inside Tomcat 7.

I have created a simple JAX-RS resource looking like this:

@Path("/")
@Produces({ "application/xml", "text/plain" })
public class ExampleResource {

    @GET
    public List<Thing> getThings() {
        List<Thing> list = new ArrayList<>();
        list.add(new Thing("a thing 1", "a thing description 1"));
        list.add(new Thing("a thing 2", "a thing description 2"));

        return list;
    }

}

Thing is a JAXB annotated POJO looking like this

        @XmlRootElement(name = "thing")
        public class Thing {
            private String name;        
            private String description;
// getters, setters and @XmlElement annotations ommited for brevity

I have also configured WadlGeneratorJAXBGrammarGenerator.class

And when I ask for GET http://localhost:8092/rest it works like a charm - nicely formatted collection of Thing is returned.

The automatically generated WADL http://localhost:8092/rest/application.wadl is almost perfect, it looks like this:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<application xmlns="http://wadl.dev.java.net/2009/02">
    <doc xmlns:jersey="http://jersey.java.net/" jersey:generatedBy="Jersey: 1.16 11/28/2012 02:09 PM" />
    <grammars>
        <include href="application.wadl/xsd0.xsd">
            <doc title="Generated" xml:lang="en" />
        </include>
    </grammars>
    <resources base="http://localhost:8092/rest/">
        <resource path="/">
            <method id="getThings" name="GET">
                <response>
                    <ns2:representation xmlns:ns2="http://wadl.dev.java.net/2009/02"
                        xmlns="" element="thing" mediaType="application/xml" />
                    <representation mediaType="text/plain" />
                </response>
            </method>
        </resource>
    </resources>
</application>

Like I said, almost perfect, and therein lies the problem.

<ns2:representation xmlns:ns2="http://wadl.dev.java.net/2009/02"
                            xmlns="" element="thing" mediaType="application/xml" />

The WADL is not describing that /getThings returns a List<Thing>. Rather, it looks like it is referring to a single element thing in the xsd0.xsd. So, when I feed it in e.g. wadl2java, it generates untyped client. In order to get a List<Thing> I have to manually code it, something like

List<Thing> asXml = root().getAsXml(new GenericType<List<Thing>>(){});

Does anyone know if it is possible to have automatic WADL generation that would somehow indicate that this particular resource is returning a List of resources of a specific type?

And I don't want to create additional "ThingList" JAXB-annotated class and return that instead in my jersey resource.

I am almost there with generating the "perfect" WADL, it is just this (hopefully) little piece that I am missing...

Thank you very much!

Imbecile answered 29/3, 2013 at 11:2 Comment(3)
I'm not too familiar with wadl, but, what (XML) value would be optimal for that line you quoted? In wsdls, lists and simple objects are represented almost in the same way.Conspiracy
It didn't come to my mind to compare with WSDL as a matter of fact since I have almost no experience with it. So you have a good point. As for what it should look like, I am not too sure about that either. Can you perhaps give an example of what it would like in WSDL?Imbecile
In a WSDL, an entity (say Person) becomes a xs:complexType with one element for each property it has. A property, say String name, looks like <xs:element minOccurs='0' name='name' nillable='true' type='xs:string'/> (the minOccurs='0' implies that is is an optional field). A property that is a list, say String[] nicknames would become something like: <xs:element maxOccurs='unbounded' minOccurs='0' name='nicknames' nillable='true' type='xs:string'/>. As you can see, the only difference from a simple field to a list is maxOccurs='unbounded'.Conspiracy
F
4

I got the same problem and solved it by generating my own WADL.

For this you need to add the following files to your project

application-doc.xml for high level WADL overview comments

application-grammers.xml which defines the location of your schema ( with your Things and Thing elements and complextypes )

resourcedoc.xml , this is generated by a maven plugin and it reads your jersey classes, which contains your response element javadoc annotations.

just add this HrWadlGeneratorConfig class to your project and add this as init param to the jersey servlet

    <init-param>
        <param-name>com.sun.jersey.config.property.WadlGeneratorConfig</param-name>
        <param-value>nl.amis.hr.wadl.HrWadlGeneratorConfig</param-value>
    </init-param> 

Class

 package nl.amis.hr.wadl;                                                                                        

 import com.sun.jersey.api.wadl.config.WadlGeneratorConfig;                                                      
 import com.sun.jersey.api.wadl.config.WadlGeneratorDescription;                                                 
 import com.sun.jersey.server.wadl.generators.WadlGeneratorApplicationDoc;                                       
 import com.sun.jersey.server.wadl.generators.WadlGeneratorGrammarsSupport;                                      
 import com.sun.jersey.server.wadl.generators.resourcedoc.WadlGeneratorResourceDocSupport;                       
 import com.sun.research.ws.wadl.Grammars;                                                                       
 import com.sun.research.ws.wadl.Include;                                                                        
 import com.sun.research.ws.wadl.ObjectFactory;                                                                  

 import java.util.List;                                                                                          

 public class HrWadlGeneratorConfig extends WadlGeneratorConfig {                                                

     @Override                                                                                                   
     public List<WadlGeneratorDescription> configure() {                                                         
         ObjectFactory obj = new ObjectFactory()  ;                                                              
         Grammars gram = obj.createGrammars();                                                                   
         Include e = obj.createInclude();                                                                        
         e.setHref("schema.xsd");                                                                                
         gram.getInclude().add(e);                                                                               

         WadlGeneratorConfigDescriptionBuilder builder = generator(WadlGeneratorApplicationDoc.class)            
         .prop( "applicationDocsStream", "application-doc.xml" )                                                 
         .generator( WadlGeneratorGrammarsSupport.class )                                                        
         .prop( "grammarsStream", "application-grammars.xml" )                                                   
         .generator( WadlGeneratorResourceDocSupport.class )                                                     
         .prop( "resourceDocStream", "resourcedoc.xml" );                                                        

         return builder.descriptions();                                                                          

     }                                                                                                           

 }                                                                                                               

Here is a snippet of the Jersey class and the @response.representation.200.qname points to the element in your own schema.xsd

  /**
  * Returns the item if existing. 
  * 
  * @response.representation.200.qname employees
  * @response.representation.200.mediaType application/xml,application/json
  * @response.representation.200.doc This is the representation returned by default
  * @response.representation.200.example {@link EmployeeExample#SAMPLE_ITEM}
  *
  *
  * @return the requested item if this service is available
  */
  @GET
  public List<Employee> getEmployees() {
     return  hrBean.getEmployeesFindAll();
  }

and the maven pom which generates the resourcedoc.xml which we be used by the WADL generator.

  <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-javadoc-plugin</artifactId>
                <version>2.4</version>
            </plugin>
        </plugins>
  </pluginManagement>                                                                                                                   

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-javadoc-plugin</artifactId>
            <executions>
                <execution>
                    <goals>
                        <goal>javadoc</goal>
                    </goals>
                    <phase>compile</phase>
                </execution>
            </executions>
            <configuration>
                <encoding>UTF-8</encoding>
                <verbose>false</verbose>
                <show>public</show>
                <subpackages>nl.amis.hr.restful</subpackages>
                <doclet>com.sun.jersey.wadl.resourcedoc.ResourceDoclet</doclet>
                    <docletPath>${path.separator}${project.build.outputDirectory}</docletPath>
                    <docletArtifacts>
                    <docletArtifact>
                          <groupId>nl.amis.hr</groupId>
                          <artifactId>Model</artifactId>
                          <version>1.0-SNAPSHOT</version>
                    </docletArtifact>
                    <docletArtifact>
                        <groupId>com.sun.jersey.contribs</groupId>
                        <artifactId>wadl-resourcedoc-doclet</artifactId>
                        <version>1.17.1</version>
                    </docletArtifact>
                    <docletArtifact>
                        <groupId>com.sun.jersey</groupId>
                        <artifactId>jersey-server</artifactId>
                        <version>1.17.1</version>
                    </docletArtifact>
                    <docletArtifact>
                        <groupId>xerces</groupId>
                        <artifactId>xercesImpl</artifactId>
                        <version>2.6.1</version>
                    </docletArtifact>
                </docletArtifacts>
                <!-- the following option is required as a work around for
                     version 2.5 of the javadoc plugin which will be used
                     by a maven version > 2.0.9 -->
                <useStandardDocletOptions>false</useStandardDocletOptions>
                <additionalparam>-output ${project.build.outputDirectory}/resourcedoc.xml</additionalparam>
            </configuration>
        </plugin>

here is the full example on github https://github.com/biemond/JDeveloper12c_12.1.2/tree/master/RestFulOWSM/WebService

Fulfillment answered 22/8, 2013 at 18:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.