| <?xml version="1.0"?> |
| <!-- |
| |
| Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved. |
| |
| This program and the accompanying materials are made available under the |
| terms of the Eclipse Public License v. 2.0, which is available at |
| http://www.eclipse.org/legal/epl-2.0. |
| |
| This Source Code may also be made available under the following Secondary |
| Licenses when the conditions for such availability set forth in the |
| Eclipse Public License v. 2.0 are satisfied: GNU General Public License, |
| version 2 with the GNU Classpath Exception, which is available at |
| https://www.gnu.org/software/classpath/license.html. |
| |
| SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 |
| |
| --> |
| |
| <!DOCTYPE chapter [<!ENTITY % ents SYSTEM "jersey.ent" > %ents; ]> |
| <chapter xmlns="http://docbook.org/ns/docbook" |
| version="5.0" |
| xml:lang="en" |
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| xmlns:xi="http://www.w3.org/2001/XInclude" |
| xmlns:xlink="http://www.w3.org/1999/xlink" |
| xsi:schemaLocation="http://docbook.org/ns/docbook http://docbook.org/xml/5.0/xsd/docbook.xsd |
| http://www.w3.org/1999/xlink http://www.w3.org/1999/xlink.xsd" |
| xml:id="wadl"> |
| |
| <title>WADL Support</title> |
| <section> |
| <title>WADL introduction</title> |
| <para> |
| Jersey contains support for |
| <link xlink:href='https://javaee.github.io/wadl/'>Web Application Description Language (WADL)</link>. WADL is |
| a XML description of a deployed RESTful web application. It contains model of the deployed resources, their |
| structure, supported media types, HTTP methods and so on. In a sense, WADL is similar to the WSDL |
| (Web Service Description Language) which describes SOAP web services. WADL is however specifically designed |
| to describe RESTful Web resources. |
| </para> |
| <important> |
| <para> |
| Since Jersey 2.5.1 the WADL generated by default is WADL in shorter form without |
| additional extension resources (OPTIONS methods, WADL resource). |
| In order to get full WADL use the query parameter <literal>detail=true</literal>. |
| </para> |
| </important> |
| <para> |
| Let's start with the simple WADL example. In the example there is a simple <literal>CountryResource</literal> |
| deployed and we request a wadl of this resource. The context root path of the application is |
| <literal>http://localhost:9998</literal>. |
| <example> |
| <title>A simple WADL example - JAX-RS resource definition</title> |
| <programlisting language="java" linenumbering="numbered">@Path("country/{id}") |
| public static class CountryResource { |
| |
| private CountryService countryService; |
| |
| public CountryResource() { |
| // init countryService |
| } |
| |
| @GET |
| @Produces(MediaType.APPLICATION_XML) |
| public Country getCountry(@PathParam("countryId") int countryId) { |
| return countryService.getCountry(countryId); |
| } |
| }</programlisting> |
| </example> |
| |
| |
| |
| The WADL of a Jersey application that contains the resource above can be requested by a |
| HTTP &lit.http.GET; request to <literal>http://localhost:9998/application.wadl</literal>. |
| Jersey will return a response with a WADL content similar to the one in the following example: |
| <programlisting language="xml" linenumbering="numbered"><![CDATA[<?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: 3.0.0 2020-12-16 13:49:07"/> |
| <grammars/> |
| <resources base="http://localhost:9998/"> |
| <resource path="country/{id}"> |
| <param xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:int" style="template" name="countryId"/> |
| <method name="GET" id="getCountry"> |
| <response> |
| <representation mediaType="application/xml"/> |
| </response> |
| </method> |
| </resource> |
| </resources> |
| </application>]]></programlisting> |
| </para> |
| <para> |
| The returned WADL is a XML that contains element <literal>resource</literal> |
| with path <literal>country/{id}</literal>. This resource has one inner <literal>method</literal> element |
| with http method as attribute, name of java method and its produced representation. This description |
| corresponds to defined java resource. Now let's look at more complex example. |
| </para> |
| |
| <para> |
| The previous WADL does not actually contain all resources exposed in our API. There are other |
| resources that are available and are hidden in the previous WADL. The previous WADL shows only resources |
| that are provided by the user. In the following example, the WADL |
| is generated using query parameter <literal>detail</literal>: |
| <literal>http://localhost:9998/application.wadl?detail</literal>. Note that usage of |
| <literal>http://localhost:9998/application.wadl?detail=true</literal> is also valid. |
| This will produce the WADL with all resource available in the application: |
| </para> |
| |
| <example> |
| <title>A simple WADL example - WADL content</title> |
| <programlisting language="xml" linenumbering="numbered"><![CDATA[<?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: 3.0.0 2020-12-16 13:49:07"/> |
| <doc xmlns:jersey="http://jersey.java.net/" jersey:hint="To get simplified WADL with user's resources only do not use the query parameter detail. Link: http://localhost:9998/application.wadl"/> |
| <grammars/> |
| <resources base="http://localhost:9998/"> |
| <resource path="country/{id}"> |
| <param xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:int" style="template" name="countryId"/> |
| <method name="GET" id="getCountry"> |
| <response> |
| <representation mediaType="application/xml"/> |
| </response> |
| </method> |
| <method name="OPTIONS" id="apply"> |
| <request> |
| <representation mediaType="*/*"/> |
| </request> |
| <response> |
| <representation mediaType="application/vnd.sun.wadl+xml"/> |
| </response> |
| <jersey:extended xmlns:jersey="http://jersey.java.net/">true</jersey:extended> |
| </method> |
| <method name="OPTIONS" id="apply"> |
| <request> |
| <representation mediaType="*/*"/> |
| </request> |
| <response> |
| <representation mediaType="text/plain"/> |
| </response> |
| <jersey:extended xmlns:jersey="http://jersey.java.net/">true</jersey:extended> |
| </method> |
| <method name="OPTIONS" id="apply"> |
| <request> |
| <representation mediaType="*/*"/> |
| </request> |
| <response> |
| <representation mediaType="*/*"/> |
| </response> |
| <jersey:extended xmlns:jersey="http://jersey.java.net/">true</jersey:extended> |
| </method> |
| </resource> |
| <resource path="application.wadl"> |
| <method name="GET" id="getWadl"> |
| <response> |
| <representation mediaType="application/vnd.sun.wadl+xml"/> |
| <representation mediaType="application/xml"/> |
| </response> |
| <jersey:extended xmlns:jersey="http://jersey.java.net/">true</jersey:extended> |
| </method> |
| <method name="OPTIONS" id="apply"> |
| <request> |
| <representation mediaType="*/*"/> |
| </request> |
| <response> |
| <representation mediaType="text/plain"/> |
| </response> |
| <jersey:extended xmlns:jersey="http://jersey.java.net/">true</jersey:extended> |
| </method> |
| <method name="OPTIONS" id="apply"> |
| <request> |
| <representation mediaType="*/*"/> |
| </request> |
| <response> |
| <representation mediaType="*/*"/> |
| </response> |
| <jersey:extended xmlns:jersey="http://jersey.java.net/">true</jersey:extended> |
| </method> |
| <resource path="{path}"> |
| <param xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:string" style="template" name="path"/> |
| <method name="GET" id="geExternalGrammar"> |
| <response> |
| <representation mediaType="application/xml"/> |
| </response> |
| <jersey:extended xmlns:jersey="http://jersey.java.net/">true</jersey:extended> |
| </method> |
| <method name="OPTIONS" id="apply"> |
| <request> |
| <representation mediaType="*/*"/> |
| </request> |
| <response> |
| <representation mediaType="text/plain"/> |
| </response> |
| <jersey:extended xmlns:jersey="http://jersey.java.net/">true</jersey:extended> |
| </method> |
| <method name="OPTIONS" id="apply"> |
| <request> |
| <representation mediaType="*/*"/> |
| </request> |
| <response> |
| <representation mediaType="*/*"/> |
| </response> |
| <jersey:extended xmlns:jersey="http://jersey.java.net/">true</jersey:extended> |
| </method> |
| <jersey:extended xmlns:jersey="http://jersey.java.net/">true</jersey:extended> |
| </resource> |
| <jersey:extended xmlns:jersey="http://jersey.java.net/">true</jersey:extended> |
| </resource> |
| </resources> |
| </application> |
| ]]></programlisting> |
| </example> |
| <para> |
| In the example above the returned application WADL is shown in full. WADL schema is defined by the |
| WADL specification, so let's look at it in more details. The root WADL document element is |
| the <literal>application</literal>. It contains global |
| information about the deployed JAX-RS application. Under this element there is a nested element |
| <literal>resources</literal> which contains zero or more <literal>resource</literal> elements. Each |
| <literal>resource</literal> element describes a single deployed resource. In our example, there are only two root |
| resources - <literal>"country/{id}"</literal> and <literal>"application.wadl"</literal>. The |
| <literal>"application.wadl"</literal> resource is the resource that was just requested in order to receive the |
| application WADL document. Even though WADL support is an additional feature in Jersey it is still |
| a resource deployed in the resource model and therefore it is itself present in the returned WADL document. |
| The first resource element with the <literal>path="country/{id}"</literal> is the element that describes our |
| custom deployed resource. |
| This resource contains a &lit.http.GET; method and three &lit.http.OPTIONS; methods. |
| The &lit.http.GET; method is our getCountry() method defined in the sample. There is a method name |
| in the <literal>id</literal> attribute and &jaxrs.Produces; is described in the |
| <literal>response/representation</literal> WADL element. &lit.http.OPTIONS; methods are the methods that |
| are automatically added by Jersey to each resource. There is an &lit.http.OPTIONS; method |
| returning <literal>"text/plain"</literal> media type, that will return a response with a string entity containing |
| the list of methods deployed on this resource (this means that instead of WADL you can use this &lit.http.OPTIONS; |
| method to get similar information in a textual representation). |
| Another &lit.http.OPTIONS; method returning <literal>*/*</literal> will return a response with no entity |
| and <literal>Allow</literal> header that will contain list of methods as a String. |
| The last &lit.http.OPTIONS; method producing <literal>"application/vnd.sun.wadl+xml"</literal> returns a |
| WADL description of the resource <literal>"country/{id}"</literal>. As you can see, all &lit.http.OPTIONS; methods |
| return information about the resource to which the HTTP &lit.http.OPTIONS; request is made. |
| </para> |
| <para> |
| Second resource with a path "application.wadl" has, again, similar &lit.http.OPTIONS; methods |
| and one &lit.http.GET; method which return this WADL. There is also |
| a sub-resource with a path defined by path param <literal>{path}</literal>. This means that you can request |
| a resource on the URI <literal>http://localhost:9998/application.wadl/something</literal>. |
| This is used only to return an external grammar if there is any attached. Such an external grammar can be |
| for example an <literal>XSD</literal> schema of the response entity which if the response entity is a JAXB bean. |
| An external grammar support via Jersey <emphasis>extended WADL support</emphasis> is described in sections below. |
| </para> |
| <para> |
| All resource that were added in this second example into the WADL contains |
| element <literal>extended</literal>. This means that this resource is not a part of a core RESTful API and |
| is rather a helper resource. If you need to mark any your own resource are extended, annotate |
| is with &jersey.server.ExtendedResource;. Note that there might be methods visible in the default simple |
| WADL even the user has not added them. This is for example the case of MVC added methods which were added |
| by &jersey.server.ModelProcessor; but are still intended to be used by the client to achieve their |
| primary use case of getting formatted data. |
| </para> |
| <para> |
| Let's now send a HTTP &lit.http.OPTIONS; request to <literal>"country/{id}"</literal> resource using the the |
| <literal>curl</literal> command: |
| <programlisting linenumbering="unnumbered">curl -X OPTIONS -H "Allow: application/vnd.sun.wadl+xml" \ |
| -v http://localhost:9998/country/15</programlisting> |
| |
| We should see a WADL returned similar to this one: |
| |
| <example> |
| <title>OPTIONS method returning WADL</title> |
| |
| <programlisting language="xml" linenumbering="numbered"><?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: 3.0.0 ${buildNumber}"/> |
| <grammars/> |
| <resources base="http://localhost:9998/"> |
| <resource path="country/15"> |
| <method name="GET" id="getCountry"> |
| <response> |
| <representation mediaType="application/xml"/> |
| </response> |
| </method> |
| <method name="OPTIONS" id="apply"> |
| <request> |
| <representation mediaType="*/*"/> |
| </request> |
| <response> |
| <representation mediaType="application/vnd.sun.wadl+xml"/> |
| </response> |
| </method> |
| <method name="OPTIONS" id="apply"> |
| <request> |
| <representation mediaType="*/*"/> |
| </request> |
| <response> |
| <representation mediaType="text/plain"/> |
| </response> |
| </method> |
| <method name="OPTIONS" id="apply"> |
| <request> |
| <representation mediaType="*/*"/> |
| </request> |
| <response> |
| <representation mediaType="*/*"/> |
| </response> |
| </method> |
| </resource> |
| </resources> |
| </application></programlisting> |
| </example> |
| The returned WADL document has the standard WADL structure that we saw in the WADL document returned for the |
| whole Jersey application earlier. The main difference here is that the only <literal>resource</literal> is the |
| resource to which the &lit.http.OPTIONS; HTTP request was sent. The resource has now path |
| <literal>"country/15"</literal> and not <literal>"country/{id}"</literal> as the path parameter |
| <literal>{id}</literal> was already specified in the request to this concrete resource. |
| </para> |
| |
| <para> |
| Another, a more complex WADL example is shown in the next example. |
| |
| <example> |
| <title>More complex WADL example - JAX-RS resource definition</title> |
| |
| <programlisting language="java" linenumbering="numbered">@Path("customer/{id}") |
| public static class CustomerResource { |
| private CustomerService customerService; |
| |
| @GET |
| public Customer get(@PathParam("id") int id) { |
| return customerService.getCustomerById(id); |
| } |
| |
| @PUT |
| public Customer put(Customer customer) { |
| return customerService.updateCustomer(customer); |
| } |
| |
| @Path("address") |
| public CustomerAddressSubResource getCustomerAddress(@PathParam("id") int id) { |
| return new CustomerAddressSubResource(id); |
| } |
| |
| @Path("additional-info") |
| public Object getAdditionalInfoSubResource(@PathParam("id") int id) { |
| return new CustomerAddressSubResource(id); |
| } |
| |
| } |
| |
| |
| public static class CustomerAddressSubResource { |
| private final int customerId; |
| private CustomerService customerService; |
| |
| public CustomerAddressSubResource(int customerId) { |
| this.customerId = customerId; |
| this.customerService = null; // init customer service here |
| } |
| |
| @GET |
| public String getAddress() { |
| return customerService.getAddressForCustomer(customerId); |
| } |
| |
| @PUT |
| public void updateAddress(String address) { |
| customerService.updateAddressForCustomer(customerId, address); |
| } |
| |
| @GET |
| @Path("sub") |
| public String getDeliveryAddress() { |
| return customerService.getDeliveryAddressForCustomer(customerId); |
| } |
| }</programlisting> |
| </example> |
| |
| The &lit.http.GET; request to <literal>http://localhost:9998/application.wadl</literal> will |
| return the following WADL document: |
| |
| <example> |
| <title>More complex WADL example - WADL content</title> |
| <programlisting language="xml" linenumbering="numbered"><?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: 3.0.0 ${buildNumber}"/> |
| <grammars/> |
| <resources base="http://localhost:9998/"> |
| <resource path="customer/{id}"> |
| <param xmlns:xs="http://www.w3.org/2001/XMLSchema" |
| type="xs:int" style="template" name="id"/> |
| <method name="GET" id="get"> |
| <response/> |
| </method> |
| <method name="PUT" id="put"> |
| <response/> |
| </method> |
| <method name="OPTIONS" id="apply"> |
| <request> |
| <representation mediaType="*/*"/> |
| </request> |
| <response> |
| <representation mediaType="application/vnd.sun.wadl+xml"/> |
| </response> |
| </method> |
| <method name="OPTIONS" id="apply"> |
| <request> |
| <representation mediaType="*/*"/> |
| </request> |
| <response> |
| <representation mediaType="text/plain"/> |
| </response> |
| </method> |
| <method name="OPTIONS" id="apply"> |
| <request> |
| <representation mediaType="*/*"/> |
| </request> |
| <response> |
| <representation mediaType="*/*"/> |
| </response> |
| </method> |
| <resource path="additional-info"> |
| <param xmlns:xs="http://www.w3.org/2001/XMLSchema" |
| type="xs:int" style="template" name="id"/> |
| </resource> |
| <resource path="address"> |
| <param xmlns:xs="http://www.w3.org/2001/XMLSchema" |
| type="xs:int" style="template" name="id"/> |
| <method name="GET" id="getAddress"> |
| <response/> |
| </method> |
| <method name="PUT" id="updateAddress"/> |
| <resource path="sub"> |
| <method name="GET" id="getDeliveryAddress"> |
| <response/> |
| </method> |
| </resource> |
| </resource> |
| </resource> |
| <resource path="application.wadl"> |
| <method name="GET" id="getWadl"> |
| <response> |
| <representation mediaType="application/vnd.sun.wadl+xml"/> |
| <representation mediaType="application/xml"/> |
| </response> |
| </method> |
| <method name="OPTIONS" id="apply"> |
| <request> |
| <representation mediaType="*/*"/> |
| </request> |
| <response> |
| <representation mediaType="text/plain"/> |
| </response> |
| </method> |
| <method name="OPTIONS" id="apply"> |
| <request> |
| <representation mediaType="*/*"/> |
| </request> |
| <response> |
| <representation mediaType="*/*"/> |
| </response> |
| </method> |
| <resource path="{path}"> |
| <param xmlns:xs="http://www.w3.org/2001/XMLSchema" |
| type="xs:string" style="template" name="path"/> |
| <method name="GET" id="geExternalGrammar"> |
| <response> |
| <representation mediaType="application/xml"/> |
| </response> |
| </method> |
| <method name="OPTIONS" id="apply"> |
| <request> |
| <representation mediaType="*/*"/> |
| </request> |
| <response> |
| <representation mediaType="text/plain"/> |
| </response> |
| </method> |
| <method name="OPTIONS" id="apply"> |
| <request> |
| <representation mediaType="*/*"/> |
| </request> |
| <response> |
| <representation mediaType="*/*"/> |
| </response> |
| </method> |
| </resource> |
| </resource> |
| </resources> |
| </application></programlisting> |
| </example> |
| |
| The <literal>resource</literal> with <literal>path="customer/{id}"</literal> is similar to the |
| country resource from the previous example. There is a path parameter which identifies the customer |
| by <literal>id</literal>. The resource contains 2 user-declared methods and again auto-generated |
| &lit.http.OPTIONS; methods added by Jersey. The resource declares 2 sub-resource locators which are |
| represented in the returned WADL document as nested <literal>resource</literal> elements. Note that the sub-resource |
| locator <literal>getCustomerAddress()</literal> returns a type CustomerAddressSubResource in the |
| method declaration and also in the WADL there is a <literal>resource</literal> element for such |
| a sub resource with full internal description. The second method |
| <literal>getAdditionalInfoSubResource()</literal> returns only an <literal>Object</literal> in the method declaration. |
| While this is correct from the JAX-RS perspective as the real returned type can be computed from a request |
| information, it creates a problem for WADL generator because WADL is generated based on the static configuration |
| of the JAX-RS application resources. The WADL generator does not know what type would be actually returned to |
| a request at run time. |
| That is the reason why the nested <literal>resource</literal> element with <literal>path="additional-info"</literal> |
| does not contain any information about the supported resource representations. |
| </para> |
| <para> |
| The <literal>CustomerAddressSubResource</literal> sub-resource described in the nested element |
| <literal><resource path="address"></literal> does not contain an &lit.http.OPTIONS; method. |
| While these methods are in fact generated by Jersey for the sub-resource, Jersey WADL generator does not currently |
| support adding these methods to the sub-resource description. This should be addressed in the near future. |
| Still, there are two user-defined resource methods handling HTTP &lit.http.GET; and &lit.http.PUT; requests. |
| The sub-resource method <literal>getDeliveryAddress()</literal> is represented as a separate nested resource with |
| <literal>path="sub"</literal>. Should there be more sub-resource methods defined with <literal>path="sub"</literal>, |
| then all these method descriptions would be placed into the same <literal>resource</literal> element. |
| In other words, sub-resource methods are grouped in WADL as sub-resources based on their <literal>path</literal> |
| value. |
| </para> |
| </section> |
| |
| <section> |
| <title>Configuration</title> |
| |
| <para> |
| WADL generation is enabled in Jersey by default. This means that &lit.http.OPTIONS; |
| methods are added by default to each resource and an auto-generated <literal>/application.wadl</literal> |
| resource is deployed too. To override this default behavior and disable WADL generation in Jersey, setup the |
| configuration property in your application: |
| |
| <programlisting>jersey.config.server.wadl.disableWadl=true</programlisting> |
| |
| This property can be setup in a <literal>web.xml</literal> if the Jersey application is deployed |
| in the servlet with <literal>web.xml</literal> or the property can be returned from the &jaxrs.core.Application;. |
| <literal>getProperties()</literal>. See <link linkend="deployment">Deployment chapter</link> for more information |
| on setting the application configuration properties in various deployments. |
| </para> |
| <para> |
| WADL support in Jersey is implemented via &jersey.server.ModelProcessor; extension. This implementation enhances |
| the application resource model by adding the WADL providing resources. WADL &lit.jersey.server.ModelProcessor; |
| priority value is high (i.e. the priority is low) as it should be executed as one of the last model processors. |
| Therefore, any &lit.jersey.server.ModelProcessor; executed before will not see WADL extensions in the resource model. |
| WADL handling resource model extensions (resources and &lit.http.OPTIONS; resource methods) are not added to the |
| application resource model if there is already a matching resource or a resource method detected in the model. |
| In other words, if you define for example your own &lit.http.OPTIONS; method that would produce |
| <literal>"application.wadl"</literal> response content, this method will not be overridden by WADL model processor. |
| See <link linkend="resource-builder">Resource builder chapter</link> for more information on |
| &lit.jersey.server.ModelProcessor; extension mechanism. |
| </para> |
| </section> |
| |
| <section> |
| <title>Extended WADL support</title> |
| <para> |
| <emphasis role="strong">Please note that the API of extended WADL support is going to be changed in one of the future |
| releases of Jersey 3.x (see below).</emphasis> |
| </para> |
| <para> |
| Jersey supports extension of WADL generation called <emphasis>extended WADL</emphasis>. Using the extended WADL |
| support you can enhance the generated WADL document with additional information, such as |
| resource method javadoc-based documentation of your REST APIs, adding general documentation, |
| adding external grammar support, or adding any custom WADL extension information. |
| </para> |
| <para> |
| <emphasis role="strong">Again, note that the extended WADL in Jersey 3.x is NOT the intended final version and |
| API is going to be changed.</emphasis> The existing set of features and functionality will be preserved but the |
| APIs will be significantly re-designed to support additional use cases. This impacts mainly the APIs of |
| &jersey.server.WadlGenerator;, &jersey.server.WadlGeneratorConfig; as well as any related classes. The API changes |
| may impact your code if you are using a custom &lit.jersey.server.WadlGenerator; or plan to implement one. |
| </para> |
| </section> |
| </chapter> |