23.4. RESTful HTTP web services with RESTEasy

Seam integrates the RESTEasy implementation of the JAX-RS specification (JSR 311). You can decide which of the following features are integrated with your Seam application:
  • RESTEasy bootstrap and configuration, with automatic resource detection. and providers.
  • SeamResourceServlet-served HTTP/REST requests, without the need for an external servlet or configuration in web.xml.
  • Resources written as Seam components with full Seam life cycle management and bijection.

23.4.1. RESTEasy configuration and request serving

First, download the RESTEasy libraries and the jaxrs-api.jar, and deploy them alongside the integration library (jboss-seam-resteasy.jar) and any other libraries your application requires.
In seam-gen based projects, this can be done by appending jaxrs-api.jar, resteasy-jaxrs.jar and jboss-seam-resteasy.jar to the deployed-jars.list (war deployment) or deployed-jars-ear.list (ear deployment) file. For a JBDS based project, copy the libraries mentioned above to the EarContent/lib (ear deployment) or WebContent/WEB-INF/lib (war deployment) folder and reload the project in the IDE.
All classes annotated with @javax.ws.rs.Path will automatically be discovered and registered as HTTP resources at start up. Seam automatically accepts and serves HTTP requests with its built-in SeamResourceServlet. The URI of a resource is built like so:
  • The URI begins with the pattern mapped in web.xml for the SeamResourceServlet — in the examples provided, /seam/resource. Change this setting to expose your RESTful resources under a different base. Remember that this is a global change, and other Seam resources (s:graphicImage) will also be served under this base path.
  • Seam's RESTEasy integration then appends a configurable string to the base path (/rest by default). So, in the example, the full base path of your resources would be /seam/resource/rest. We recommend changing this string in your application to something more descriptive — add a version number to prepare for future REST API upgrades. This allows old clients to keep the old URI base.
  • Finally, the resource is made available under the defined @Path. For example, a resource mapped with @Path("/customer") would be available under /seam/resource/rest/customer.
The following resource definition would return a plain text representation for any GET request using the URI http://your.hostname/seam/resource/rest/customer/123:
@Path("/customer")
public class MyCustomerResource {

    @GET
    @Path("/{customerId}")
    @Produces("text/plain")
    public String getCustomer(@PathParam("customerId") int id) {
         return ...;
    }

}
If these defaults are acceptable, there is no need for additional configuration. However, if required, you can configure RESTEasy in your Seam application. First, import the resteasy namespace into your XML configuration file header:
<components
   xmlns="http://jboss.com/products/seam/components"
   xmlns:resteasy="http://jboss.com/products/seam/resteasy"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation=
     "http://jboss.com/products/seam/resteasy
      http://jboss.com/products/seam/resteasy-2.2.xsd
      http://jboss.com/products/seam/components
      http://jboss.com/products/seam/components-2.2.xsd">
<resteasy:application resource-path-prefix="/restv1"/>
The full base path to your resources is now /seam/resource/restv1/{resource}. Note that your @Path definitions and mappings do not change. This is an application-wide switch, usually used for versioning of the HTTP API.
If you want to map the full path in your resources, you can disable base path stripping:
<resteasy:application strip-seam-resource-path="false"/>
Here, the path of a resource is now mapped with @Path("/seam/resource/rest/customer"). Disabling this feature binds your resource class mappings to a particular deployment scenario. This is not recommended.
Seam scans your classpath for any deployed @javax.ws.rs.Path resources or @javax.ws.rs.ext.Provider classes. You can disable scanning and configure these classes manually like so:
<resteasy:application
     scan-providers="false"
     scan-resources="false"
     use-builtin-providers="true">

  <resteasy:resource-class-names>
    <value>org.foo.MyCustomerResource</value>
    <value>org.foo.MyOrderResource</value>
         <value>org.foo.MyStatelessEJBImplementation</value>
  </resteasy:resource-class-names>

  <resteasy:provider-class-names> 
    <value>org.foo.MyFancyProvider</value> 
  </resteasy:provider-class-names> 

 </resteasy:application>
The use-built-in-providers switch enables (default) or disables the RESTEasy built-in providers. Since these provide plain text, JSON and JAXB marshaling, we recommend that these are left enabled.
RESTEasy supports plain EJBs (EJBs that are not Seam components) as resources. Instead of configuring the JNDI names in a non-portable fashion in web.xml (see RESTEasy documentation), you can simply list the EJB implementation classes, not the business interfaces, in components.xml as shown above. Note that you have to annotate the @Local interface of the EJB with @Path, @GET, and so on - not the bean implementation class. This allows you to keep your application deployment-portable with the global Seam jndi-pattern switch on <core:init/>. Note that plain (non-Seam component) EJB resources will not be found even if scanning of resources is enabled, you always have to list them manually. Again, this whole paragraph is only relevant for EJB resources that are not also Seam components and that do not have an @Name annotation.
Finally, you can configure media type and language URI extensions:
<resteasy:application>

    <resteasy:media-type-mappings>
      <key>txt</key>
      <value>text/plain</value>
    </resteasy:media-type-mappings>

    <resteasy:language-mappings>
       <key>deutsch</key><value>de-DE</value>
    </resteasy:language-mappings>

</resteasy:application>
This definition would map the URI suffix of .txt.deutsch to the additional Accept and Accept-Language header values, text/plain and de-DE.