(Quick Reference)

JAX-RS Project

Authors: Bud Byrd, Donald Jackson, Martin Krasser, Davide Cavestro, Noam Y. Tenne

Version: 3.1.0

1 Introduction

The jaxrs project is a set of Grails plugins that supports the development of RESTful web services based on the Java API for RESTful Web Services (JSR 311: JAX-RS).

It is targeted at developers who want to structure the web service layer of an application in a JSR 311 compatible way but still want to continue to use Grails' powerful features such as GORM, automated XML and JSON marshalling, Grails services, Grails filters and so on. This plugin is an alternative to Grails' built-in mechanism for implementing RESTful web services.

Features

  • Makes the JSR 311 (JAX-RS) available to Grails applications for developing RESTful web services.
  • New Grails artefact types, Resource and Provider, for JAX-RS classes.
    • JAX-RS Resource classes under grails-app/resources are auto-detected and can be modified at runtime.
    • JAX-RS Provider classes under grails-app/providers are auto-detected and can be modified at runtime.
  • Extended Grails command line interface
    • Create new resources and unit test templates via grails create-resource <resource name>.
    • Generate ready-to-use resources from domain objects via grails generate-resources <domain class name>.
  • Scaffolding
    • Generate RESTful service interfaces for Grails domain objects.
    • Content negotiation support for XML and JSON representations.
  • Ability to use any Grails feature within JAX-RS resources and providers such as:
  • Entity providers
    • Domain object providers that convert between Grails domain objects and XML or JSON representations.
    • Support classes for developing custom entity providers.
    • Support for content negotiation based on the Accept request header.
  • Easy integration testing of JAX-RS resources and providers.
  • Plugin users may choose between Jersey and Restlet as JAX-RS implementations by means of configuration.
  • jaxrs applications can be deployed to Google App Engine (GAE).

2 Quick Start

Create The Application

Use Grails 3.x to create a new application. As an example, let's create an application called jaxrs-example:
[budjb@laptop Projects]$ grails create-app jaxrs-example
| Application created at /Users/budjb/Projects/jaxrs-example

Add JAX-RS Plugin to Dependencies

In the build.gradle file, add the plugin to the project's dependencies. For the example, we'll use the Jersey 1.x implementation.

dependencies {
    compile "org.grails.plugins:jaxrs-jersey1:1.0.0"

// other dependencies below… }

Be sure to use the updated version number of the plugin you are using. The version number above is likely out of date.

Create a Resource

The plugin comes bundled with a helper script to generate a basic resource, which we'll use here.

[budjb@laptop jaxrs-example]$ grails create-resource com.budjb.Test

BUILD SUCCESSFUL

| Rendered template Resource.groovy to destination grails-app/resources/com/budjb/TestResource.groovy

The resulting file should look like the class below. Notice the path information in the generated Resource.

package com.budjb

import javax.ws.rs.GET import javax.ws.rs.Path import javax.ws.rs.Produces

@Path('/api/test') class TestResource { @GET @Produces('text/plain') String getTestRepresentation() { 'Test' } }

Start the Application

Everything we need is in place, so now we can start the application.
[budjb@laptop jaxrs-example]$ ./gradlew bootRun
Grails application running at http://localhost:8080 in environment: development
> Building 97% > :jaxrs-example:bootRun

Try It Out!

Point your web browser to http://localhost:8080/api/test, and you should be greeted with the word Test.

3 Installing

The plugin itself is split into several smaller plugins. The jaxrs-core plugin contains the bulk of the classes necessary for the plugin to work, but there are many different implementations of JSR-311 that exist. The plugin was broken up to better manage the library dependencies that come with adding many different implementations.

When adding the jaxrs plugin to an application, one of the implementation-specific plugins should be used.

The jaxrs-core plugin should not be included as a dependency of an application directly. It will automatically be included as part of the dependencies of the implementation that is chosen.

The table below details the various plugins that are available and what they do.

NameDescription
jaxrs-coreContains the core classes necessary to run the jaxrs plugin. This plugin should not be included directly in applications.
jaxrs-jersey1Implements the jersey server 1.x JAX-RS library.
jaxrs-restletImplements the restlet JAX-RS library.
jaxrs-integration-testProvides a mocked environment superclass useful for integration tests that target resources.

4 Resources

4.1 What Are Resources

Root resources are classes that contain RESTful API services as defined by the JSR-311 JAX-RS standard. Such classes contain methods that service an API endpoint. These classes and methods make extensive use of annotations to define their properties and behavior, such as the path in a URL, what content types endpoints consume and produce, and what HTTP methods each endpoint supports.

Oracle has an excellent article explaining how to create root resource classes and detail the annotations provided byJAX-RS.

4.2 Creating Resources

Any *Resource.groovy file created under grails-app/resources is assumed to be a JAX-RS resource and auto-detected by the jaxrs plugin. These resources are checked for the presence of JAX-RS annotations as defined by JAX-RS 1.1 specification, section 3.1. Resources that aren't properly annotated are ignored by the plugin.

When running applications locally, resource classes are watched and reloaded when any change to them occurs.

4.3 Generating Resources

As a convenience, the jaxrs plugin provides a script that will create a simple resource skeleton that can be built upon. The default template generates a simple root resource class with a single method implementing a GET API. The script can be called as follows:

grails create-resource class.path.Name

In the above example, a new resource class will be generated at the path grails-app/resources/class/path/NameResource.groovy with an API root path of /api/name.

The default template can be overridden by applications by placing a new template in src/main/templates/artifacts/Resource.groovy. Use the default template as a reference on the variables used to build the resource class.

A more powerful script that will generate root resources for a domain class is documented in the Scaffolding Domains section.

5 Entity Providers

Entity providers bind representation formats to Java classes. They are used to factor out marshalling and unmarshalling code from resource classes.

The jaxrs plugin provides some default entity providers that are presented in the following subsections. The custom providers section explains how to implement custom entity providers.

5.1 Domain Object Providers

Domain object providers convert between Grails domain classes and their XML or JSON representations and support content negotiation.
  • Converting an XML or JSON representation to a domain object is done by the org.grails.jaxrs.provider.DomainObjectReader. This provider is used whenever a Grails domain class is used as resource method parameter.
  • Converting a domain object to an XML or JSON representation is done by the org.grails.jaxrs.provider.DomainObjectWriter. This provider is used whenever a Grails domain object (collection) is returned from a resource method.

The behaviour of domain object providers can be customized as described in the custom providers section.

5.2 XML Providers

XML providers are superseded by domain object providers since jaxrs version 0.3.
  • org.grails.jaxrs.provider.XMLReader converts an XML representation of a domain object into a java.util.Map. This map can be used for constructing domain objects.
  • org.grails.jaxrs.provider.XMLWriter converts an grails.converters.XML object into an XML representation.

Usage example:

import grails.converters.XML

class PersonResource { @PUT @Consumes('application/xml') @Produces('application/xml') XML update(Map dto) { Person person = new Person(map) // … do something with person return person as XML } }

5.3 JSON Providers

JSON providers are superseded by domain object providers since jaxrs version 0.3.
  • org.grails.jaxrs.provider.JSONReader converts a JSON representation of a domain object into a java.util.Map. This map can be used for constructing domain objects.
  • org.grails.jaxrs.provider.JSONWriter converts an grails.converters.JSON object into a JSON representation.

Usage example:

import grails.converters.JSON

class PersonResource { @PUT @Consumes('application/json') @Produces('application/json') JSON update(Map dto) { Person person = new Person(map) // … do something with person return person as JSON } }

5.4 Custom Providers

Applications can implement their own entity providers by placing them into the grails-app/providers directory. In order to be auto-detected by jaxrs they:
  • must be annotated with javax.ws.rs.ext.Provider.
  • must have a file name matching *Reader.groovy if the corresponding class implements javax.ws.rs.ext.MessageBodyReader.
  • must have a file name matching *Writer.groovy if the corresponding class implements javax.ws.rs.ext.MessageBodyWriter.

Custom Domain Object Providers

For customizing the conversion between Grails domain objects and their XML or JSON representations, one has to disable the default domain object providers first. To disable the default domain object reader and writer, the following entries must be added to application configuration:

  • org.grails.jaxrs.doreader.disable = true
  • org.grails.jaxrs.dowriter.disable = true

In the following example a custom domain object writer is implemented, therefore, only the default domain object writer needs to be disabled. A custom XML creation should be done for the Person domain class (see scaffolding example), for all other classes the default XML creation should occur. Here's the custom provider.

package hello

import javax.ws.rs.Produces import javax.ws.rs.ext.Provider import groovy.xml.MarkupBuilder import org.grails.jaxrs.support.DomainObjectWriterSupport

@Provider @Produces(['text/xml', 'application/xml', 'text/x-json', 'application/json']) class CustomDomainObjectWriter extends DomainObjectWriterSupport { protected Object writeToXml(Object obj, OutputStream entityStream, String charset) { if (obj instanceof Person) { def writer = new OutputStreamWriter(entityStream, charset) def builder = new MarkupBuilder(writer) builder.person { id(obj.id) fullName("${obj.firstName} ${obj.lastName}") } } else { super.writeToXml(obj, entityStream, charset) } } }

The custom provider overrides the writeToXml method and generates custom XML using a MarkupBuilder. To test this provider, create an application as described in the scaffolding example, create a folder grails-app/provider/hello, and place this custom provider there. The plugin will auto-detect the provider. To create a new person object in the database, send the following request:

POST /api/person HTTP/1.1
Content-Type: application/xml
Accept: application/xml
Host: localhost:8080
Content-Length: 83

<person> <firstName>Custom</firstName> <lastName>Tester</lastName> </person>

The response entity is a custom XML representation created by the custom provider:

HTTP/1.1 201 Created
Content-Type: application/xml
Location: http://localhost:8080/api/person/3
Transfer-Encoding: chunked
Server: Jetty(6.1.14)

<person> <id>3</id> <fullName>Custom Tester</fullName> </person>

There are several other protected DomainObjectWriterSupport methods for customizing the domain object marshalling, for example writeToJson to create custom JSON representations or isWriteable to narrow the set of domain classes that a custom domain object writer accepts. Refer to the the API docs for details.

Further Entity Provider Support

For simple use cases, the jaxrs plugin additionally provides the abstract classes:

  • org.grails.jaxrs.support.MessageBodyReaderSupport<T>
  • org.grails.jaxrs.support.MessageBodyWriterSupport<T>

These base classes can also be used for classes other than domain classes. Implementors define the supported Java type with a type parameter. For example, the following class is a MessageBodyWriter that supports conversions for a Note class.

@Provider
@Produces('application/xml')
class NoteWriter extends MessageBodyWriterSupport<Note> {
    void writeTo(Note entity, MultivaluedMap httpHeaders, OutputStream entityStream) {
        def builder = new MarkupBuilder(new OutputStreamWriter(entityStream))
        builder.note {
            // create custom XML here …
        }
    }
}

Similarly, given a POJO named UserDto, the following reader provides object instances from their JSON representation:

@Provider
@Consumes("application/json")
class UserDtoReader extends MessageBodyReaderSupport<UserDto> {
    @Override
    public UserDto readFrom(MultivaluedMap<String, String> httpHeaders,
            InputStream entityStream) throws IOException,
            WebApplicationException {
        return new JsonSlurper().parse(new InputStreamReader(entityStream))
    }
}

For details about the MessageBodyWriterSupport and MessageBodyReaderSupport classes refer to the API docs.

Alternatively, you may of course write JAX-RS providers from scratch by using the JAX-RS API directly.

6 Configuration

While the plugin works well out of the box without any configuration, there are several configuration options available to change certain behaviors of the plugin.

JAX-RS resource scope

By default, JAX-RS resource classes are instantiated with every request which corresponds to the following entry in the application configuration:

org.grails.jaxrs.resource.scope = 'prototype'

Since this is the default you can omit this entry as well. On the other hand, if you prefer that your JAX-RS resources are singletons, add the following configuration entry.

org.grails.jaxrs.resource.scope = 'singleton'

Domain object providers

From version 0.3 onwards the jaxrs plugin comes with JAX-RS providers for converting between Grails domain objects and XML/JSON representations. Domain object providers are explained in detail in the domain object providers section. Domain object readers and writers can be disabled by adding the following entries to the application configuration.

org.grails.jaxrs.doreader.disable = true
org.grails.jaxrs.dowriter.disable = true

This is useful in situations where applications implement custom providers. Another domain object provider configuration property, org.grails.jaxrs.dowriter.require.generic.collections, is explained in the domain object collections section.

Additional Providers

This feature is only available when the plugin uses the Jersey implementation.

By default the jaxrs plugin scans the grails-app/providers directory for custom providers. JAX-RS provider implementations located elsewhere (e.g. in 3rd party libraries) are ignored. This can be changed by defining extra paths where the plugin should scan for additional providers. For example by adding the following to the application configuration the plugin additionally scans the packages com.foo and com.bar for providers.

org.grails.jaxrs.provider.extra.paths = 'com.foo;com.bar'

You can also define extra paths by setting the corresponding init parameter.

org.grails.jaxrs.provider.init.parameters = ['com.sun.jersey.config.property.packages': 'com.foo;com.bar']

Init Parameters

Init parameters for the servlet of the underlying JAX-RS implementation can be set via the org.grails.jaxrs.provider.init.parameters configuration property in the application configuration, as in the following example.

org.grails.jaxrs.provider.init.parameters = [
    'com.sun.jersey.config.property.packages': 'com.foo;com.bar',
    'another.key': 'another.value'
]

7 Swagger Integration

With the jersey1 implementation of the JAX-RS plugin, Swagger 2.0 support is built-in, although it is disabled by default.

When Swagger is enabled, the /swagger.json endpoint is exposed containing the details about the application's API services, assuming the resources are annotated with the proper Swagger annotations.

Configuration

All of the Swagger configuration options are set under the path org.grails.jaxrs.swagger. The following options are available.

Configuration PropertyRequiredDescriptionTypeDefault
enabledIf true, /swagger.json will be exposed with details regarding the API service.Booleanfalse
beanConfigClassName The fully qualified class name of a custom instance of BeanConfig used to provide information about the API service. This is useful when applications need to provide additional information, such as security requirements.String 
resourcePackageThe package that swagger should scan for JAX-RS resources. Multiple packages may be provided as a comma-separated list.String 
version The API version number.String1
title The title of the API service. If this is not set, the application name is used.StringApplication name.
description The description of the API service.String 
contact Contact information.String 
license License name.String 
licenseUrl URL to information about the license.String 
scan Whether Swagger should scan for resources.Booleantrue
baseUrl The base URL to the API service. This is useful when the application lives behind a load balancer.StringThe application's discovered base URL.

Swagger UI

When the jaxrs-swagger-ui plugin is included in an application, the Swagger UI is exposed with the path /showRestApi. The UI has been modified only in that it is hardcoded to query the application itself for the swagger.json information.

8 Integration Testing

The jaxrs-integration-test plugin contains classes that make integration testing resources much easier.

Integration tests for resources are created in the same way that other integration tests are created, except that the test spec classes should extend JaxrsIntegrationSpec. This class sets up a mocked servlet context that tests can use to send mocked requests through the JAX-RS servlet stack, effectively emulating the path real requests would take.

Integration tests will use the JAX-RS implementation that is included in the project.

JaxrsIntegrationSpec

An example of a test may look something like:

package com.budjb

import grails.test.mixin.integration.Integration import org.grails.plugins.jaxrs.test.JaxrsIntegrationSpec import org.grails.plugins.jaxrs.test.JaxrsRequestProperties

@Integration class TestResourceSpec extends JaxrsIntegrationSpec { def 'Ensure GET /api/test returns the correct content'() { when: def response = makeRequest(new JaxrsRequestProperties(method: 'GET', uri: '/api/test'))

then: response.bodyAsString == 'Test' response.status == 200 }

/** * Return the list of additional resources to build the JAX-RS servlet with. * * @return */ @Override List getResources() { return [] } }

Classes that extend JaxrsIntegrationSpec are required to implements the getResources method. This method is expected to return a list of classes that represent additional resources or providers that should be loaded by the JAX-RS implementation. This method is useful when there are test-specific resources or providers that tests require to operate. The advantage is that these test-specific classes need not be present on the classpath when the application is deployed, and so do not need to exist in the src/main folder.

Making Requests

The JaxrsIntegrationSpec contains a makeRequest method that should be used to make requests to a resource. This method sets up servlet requests and response objects, and hands the request off properly. The makeRequest method takes a JaxrsRequestProperties object as its parameter. This object contains several properties that make up a request.

PropertyDescription
uriPath of the request. This does not need the whole hostname of running application, but only the path to the resource being tested.
methodThe string HTTP method to use with the request. Common values are GET , POST , PUT , and DELETE .
contentTypeThe content type of the body of the request.
acceptThe requested content type of the body of the response.
headersA map of headers, where the key is the name of the header and the value is the value of the header. Supports multi-valued headers.
characterEncodingCharacter encoding of the request. Defaults to UTF-8 .

The makeRequest method returns a JaxrsResponseProperties object containing important properties of the response, as well as a couple of convenience methods for converting the response body.

Properties

PropertyDescription
statusThe HTTP status code of the response.
bodyThe body of the response, if applicable. This property is a byte array.
contentTypeThe content type of the response, if applicable.
headersThe headers of the response.

Methods

MethodDescription
getBodyAsString()Returns the body of the response as a String.
getBodyAsJson()Parses the body of the response as JSON, and returns either a List or a Map.
getBodyAsXml()Parses the body of the response as XML, and returns a GPathResult.

9 Advanced Features

9.1 Generate WADL

Automatically generated WADL functionality is only available in version 0.4 of the jaxrs plugin or higher, and requires the Jersey implementation.

A WADL document for resources managed by the plugin can be generated by sending a GET request to /application.wadl. The result should look like:

<application xmlns="http://research.sun.com/wadl/2006/10">
  <doc xmlns:jersey="http://jersey.dev.java.net/" jersey:generatedBy="Jersey: 1.1.4.1 11/24/2009 01:30 AM"/>
  <resources base="http://localhost:8080/">
    <resource path="/api/test">
      <method name="GET" id="getTestRepresentation">
        <request>
          <param xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:string" style="query" name="name"/>
        </request>
        <response>
          <representation mediaType="text/plain"/>
        </response>
      </method>
    </resource>
  </resources>
</application>

9.2 Scaffolding Domains

The jaxrs plugin also supports scaffolding. It allows you to generate a RESTful service interface for one or more domain classes based on JAX-RS resource classes. Supported representation formats are XML and JSON. The following sections walk through a simple example.

Create a domain class

To create a Person domain class go to the project's root directory and enter:

grails create-domain-class person

Open the generated Person.groovy file (under grails-app/domain) and add two properties, firstName and lastName.

package hello

class Person {

static constraints = { }

String firstName

String lastName

}

Generate the REST API

To generate JAX-RS resources that implement the RESTful service interface for that domain class enter:

grails generate-resources hello.Person

This will generate two resource classes, PersonCollectionResource.groovy and PersonResource.groovy (in the hello package) that support HTTP POST, GET, PUT and DELETE operations for creating, reading, updating and deleting Person objects, respectively. PersonCollectionResource.groovy is related to Person lists, PersonResource.groovy is related to individual Person instances. Let's take a look at how to use the generated RESTful service interface.

Use the REST API

Start the hello application with:

grails run-app

New person objects can be created by POSTing to http://localhost:8080/api/person. The following request POSTs an XML representation of a person object.

POST /api/person HTTP/1.1
Content-Type: application/xml
Accept: application/xml
Host: localhost:8080
Content-Length: 82

<person> <firstName>Sam</firstName> <lastName>Hill</lastName> </person>

The Content-Type header must be set either to application/xml. After sending the request, the server creates a new person object in the database and returns an XML representation of it.

HTTP/1.1 201 Created
Content-Type: application/xml
Location: http://localhost:8080/api/person/1
Transfer-Encoding: chunked
Server: Jetty(6.1.14)

<?xml version="1.0" encoding="UTF-8"?> <person id="1"> <firstName>Sam</firstName> <lastName>Hill</lastName> </person>

The client explicitly requested an XML representation via the Accept request header. Note that the returned representation differs from the submitted representation by an id attribute in the <person> element. This id is also contained in the Location response header, the URL of the created resource. The response code is 201 (CREATED). Let's create another person object using a JSON representation. Here's the request:

POST /api/person HTTP/1.1
Content-Type: application/json
Accept: application/json
Host: localhost:8080
Content-Length: 58

{"class":"Person","firstName":"Fabien","lastName":"Barel"}

The response also contains a JSON representation of the created person (see Accept request header). The id of the created person object is 2.

HTTP/1.1 201 Created
Content-Type: application/json
Location: http://localhost:8080/api/person/2
Transfer-Encoding: chunked
Server: Jetty(6.1.14)

{"class":"Person","id":"2","firstName":"Fabien","lastName":"Barel"}

Content negotiation via Content-Type and Accept headers works for other HTTP methods as well. To GET a list of created persons, open a browser (Firefox in our example) and enter the URL http://localhost:8080/api/person. This returns an XML representation of the list of persons stored in the database.

<list>
    <person id="1">
        <firstName>Sam</firstName>
        <lastName>Hill</lastName>
    </person>
    <person id="2">
        <firstName>Fabien></firstName>
        <lastName>Barel</lastName>
    </person>
</list>

An XML representation is returned because Firefox sets an Accept=text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8 request header. To get the representation of a single person, specify the id in the URL. For example, to get the person with id 1 use http://localhost:8080/api/person/1

<person id="1">
    <firstName>Sam</firstName>
    <lastName>Hill</lastName>
</person>

If you try to get a person that doesn't exist, an error message (with a status code 404) is returned.

<error>Person with id 3 not found</error>

In the next step we update the first name of person 1 by PUTting a new representation to http://localhost:8080/api/person/1.

PUT /api/person/1 HTTP/1.1
Content-Type: application/xml
Accept: application/xml
Host: localhost:8080
Content-Length: 85

<person> <firstName>Samuel</firstName> <lastName>Hill</lastName> </person>

The response is a new representation of the updated person.

HTTP/1.1 200 OK
Content-Type: application/xml
Transfer-Encoding: chunked
Server: Jetty(6.1.14)

<?xml version="1.0" encoding="UTF-8"?> <person id="1"> <firstName>Samuel</firstName> <lastName>Hill</lastName> </person>

GETting the person list again shows the update of person 1.

<list>
    <person id="1">
        <firstName>Samuel</firstName>
        <lastName>Hill</lastName>
    </person>
    <person id="2">
        <firstName>Fabien></firstName>
        <lastName>Barel</lastName>
    </person>
</list>

Finally, we delete person 1 by sending a DELETE request to http://localhost:8080/api/person/1.

DELETE /api/person/1 HTTP/1.1
Accept: application/xml
Host: localhost:8080

GETting the person lists again shows that person 1 has actually been deleted.

<list>
    <person id="2">
        <firstName>Fabien></firstName>
        <lastName>Barel</lastName>
    </person>
</list>

9.3 Using GORM

This section explains what's happening behind the scenes of the scaffolding example and how GORM inside JAX-RS resource classes.

PersonCollectionResource.groovy

Here's the source code for PersonCollectionResource.groovy.

package hello

import static org.grails.jaxrs.response.Responses.*

import javax.ws.rs.Consumes import javax.ws.rs.GET import javax.ws.rs.Produces import javax.ws.rs.Path import javax.ws.rs.PathParam import javax.ws.rs.POST import javax.ws.rs.core.Response

@Path('/api/person') @Consumes(['application/xml','application/json']) @Produces(['application/xml','application/json']) class PersonCollectionResource {

@POST Response create(Person dto) { created dto.save() }

@GET Response readAll() { ok Person.findAll() }

@Path('/{id}') PersonResource getResource(@PathParam('id') String id) { new PersonResource(id:id) } }

It is based on JSR 311 classes and annotations and uses static methods from org.grails.jaxrs.response.Responses. This is a helper class provided by the plugin that implements a very simple DSL consisting of elements created and ok. Supported content types for requests and responses are application/xml and application/json. This is given by the class-level Consumes and Produces annotations.

The PersonCollectionResource class responds to HTTP operations that are related to person lists. The URL of the person list is http://localhost:8080/api/person where the /api/person path is defined by the class-level Path('/api/person') annotation.

  • The create method responds to POST requests by storing a new Person object in the database using GORM. The XML or JSON request entity is converted by the plugin to a Person domain object and passed to the method via a dto parameter. The conversion is done by a domain object provider. The persisted domain object is passed to the created method which creates a response from it using the JAX-RS API (see source code for details). The created method constructs a URI for the Location response header from the domain object id. The Person object is set to the Response entity.
  • The readAll method responds to GET requests and returns a person list. Again we use GORM to get all person objects from the database and pass that list as argument to the ok method. This method uses the JAX-RS API to create a response (see link source code for details).
  • The getResource method creates another JAX-RS resource whenever a request to the URI template http://localhost:8080/api/person/{id} is made. The id path parameter in the template is bound to the id parameter of the getResource method. The created JAX-RS PersonResource is then used by the JAX-RS runtime to handle the request to the person with the given id.

PersonResource.groovy

Here's the source code for PersonResource.groovy.

package hello

import static org.grails.jaxrs.response.Responses.*

import javax.ws.rs.Consumes import javax.ws.rs.DELETE import javax.ws.rs.GET import javax.ws.rs.Produces import javax.ws.rs.PUT import javax.ws.rs.core.Response

import org.grails.jaxrs.provider.DomainObjectNotFoundException

@Consumes(['application/xml','application/json']) @Produces(['application/xml','application/json']) class PersonResource {

def id

@GET Response read() { def obj = Person.get(id) if (!obj) { throw new DomainObjectNotFoundException(Person.class, id) } ok obj }

@PUT Response update(Person dto) { def obj = Person.get(id) if (!obj) { throw new DomainObjectNotFoundException(Person.class, id) } obj.properties = dto.properties ok obj }

@DELETE void delete() { def obj = Person.get(id) if (obj) { obj.delete() } } }

The id property is set during construction of the resource and is used for database operations. This class implements the methods read, update and delete to handle GET, PUT and DELETE requests, respectively. It also uses GORM for database operations and relies on helper methods of org.grails.jaxrs.response.Responses to create responses via the JAX-RS API.

If there's no person with given id in the database, a DomainObjectNotFoundException is thrown. This exception class generates a custom 404 response using the JAX-RS API (see source code for details).

9.4 Applying Filters

Grails filters can be applied to JAX-RS resources as well. For example, to add a filter for the /api/test/ URL pattern, create a file TestFilters.groovy under grails-app/conf that looks like:

Filters have been deprecated in Grails 3. This documentation will be updated with details about using interceptors.

class TestFilters {

def filters = {

testUris(uri:'/api/test/**') { before = { // do some preprocessing } after = { // do some postprocessing }

} } }

9.5 Service Injection

Services can be auto-injected into resource and provider objects by name. Assue we have a service class named TestService.groovy in grails-app/services that looks like:

package hello

class TestService {

String greet(String name) { 'Hello ' + (name ? name : 'unknown') } }

We can then auto-inject the service by defining a testService property like in the following resource class.

package hello

@Path('/api/test') class TestResource {

def testService // injected

@GET @Produces('text/plain') String getTestRepresentation(@QueryParam('name') String name) { testService.greet(name) } }

9.6 Google App Engine

This section describes how to get the hello world example running on Google App Engine.

This section has been untested with Grails 3. If this documentation is out of date, please submit an issue or contribute updated documentation in a pull request.
  • Install the Grails app-engine plugin.
  • Create a Grails application and JAX-RS resource as described in the hello world example.
  • Be sure to use the jaxrs-restlet implementation plugin.
  • Add the following entries to the Grails configuration:

// replace <application-name> with the
// actual App Engine application name
google.appengine.application='<application-name>'
  • Open a shell at the root directory of the hello world application.
  • Set the application version to 1 with:

grails set-version 1
  • Run the application locally with grails app-engine run.
  • Enter the URL http://localhost:8080/test?name=Tester into your browser and the browser window should display Hello Tester .
  • Package the plugin with grails app-engine package.
  • Deploy the application with the appcfg command-line tool from your App Engine SDK.
    • On Linux, enter:

$APPENGINE_HOME/bin/appcfg.sh update ./target/war
    • On Windows, enter:

%APPENGINE_HOME%binappcfg.cmd update .targetwar
  • When prompted enter email and password to authenticate at Google App Engine.
  • Once deployment is done go enter the URL http://<application-name>.appspot.com/test?name=Tester into your browser and the browser window should display Hello Tester . It may take 10-20 seconds for Google App Engine to initialize the Grails application the first time. Subsequent requests are served much faster.

Using scaffolding together with the gorm-jpa plugin is not supported at the moment. A related feature request has already been added to the issue tracker.

10 Acknowledgements

The jaxrs plugin has a long history and has had many contributions. This section will serve to acknowledge those contributions and give proper credit and thanks for everyone's work.

The biggest thanks go to Martin Krasser, Davide Cavestro, and Noam Y. Tenne for their work on the development and maintenance of the plugin. The plugin may have gone through some structural changes, but the code and logic is either mostly intact or derived from their work. Additionally, the documentation includes significant sections of the original plugin documentation from the GitHub wiki.

Thank you also to Donald Jackson for his work on starting the adaption of the plugin for Grails 3.

11 Changelog

11.1 Grails 3.x

Version 3.1.0

  • Upgrade to support Grails 3.3.x (huge thanks Alex Stoia!)

Version 3.0.4

  • Integrate Swagger into the jaxrs-jersey1 plugin.
  • Introduce the jaxrs-swagger-ui plugin.

Version 3.0.3

  • Added missing jersey-client dependency for the jersey1 plugin. (#25)
  • Refactored JAX-RS servlet initialization order due to call order differences between the embedded tomcat server and the standalone tomcat server. (#26)

Version 3.0.2

  • Add ResourceRegistrar and ScanningResourceRegistrar so that applications and plugins can provide a set of resources or providers outside of the normal artefact scanning process.
  • Move integration tests out of the jaxrs-core plugin and into the jaxrs-integration-test plugin.
  • Add tests to the jaxrs-restlet plugin.
  • Changed how URL mappings work:
  • URL mappings are no longer configured statically via application configuration.
  • URL mappings are compiled by scanning resource classes and their methods, and a new URL mapping entry will be added per unique path. This works for both resource classes present in grails-app/resources and other resource classes registered via other means.
  • Update restlet to 2.3.6.

Version 3.0.1

  • Fix jaxrs-core plugin descriptor class name.
  • Compile the plugin with JDK 1.7 compatibility.
  • Update authors.
  • Fill in missing information in plugin descriptor files.
  • Lowered Grails version requirement to 3.0.0.

Version 3.0.0

This is the initial release of the jaxrs project for Grails 3. Structurally, this is a major refactor from the existing codebase. Procedurally, the plugin has not changed much.

Major changes include:

  • Plugin has been broken up into several plugins.
    • jaxrs-core contains the base logic for the plugin but will not work standalone.
    • jaxrs-jersey1 uses the Jersey 1.9 implementation.
    • jaxrs-restlet uses the Restlet 2.1.4 implementation.
    • jaxrs-integration-test provides base classes to test resources in integration tests.
  • Most source files have been changed from *.java to *.groovy files.
  • Many class packages have changed, and all class packages have been moved under org.grails.plugins.jaxrs.
  • Grails-generated documentation has been created.
  • Ownership and maintenance of the project has been transferred.

11.2 Grails 2.x

Version 0.11

Version 0.11 of the plugin is a release of the Grails 2.4.x compatibility branch and is probably not compatible with any previous versions.
  • Grails 2.4.x compatibility modifications.

Version 0.10

Version 0.10 of the plugin is a release of the Grails 2.3.x compatibility branch and is probably not compatible with any previous versions.
  • Re-introduced Spock testing infrastructure using Spock bundled with Grails 2.3.x
  • Includes all fixes and features added to the release of version 0.9.
  • Grails 2.3.x compatibility modifications.
  • Upgrade to Restlet 2.1.4.

Version 0.9

To improve the compatibility of this plugin across Groovy and Grails versions, the Spock test infrastructure has been removed and is now available through the new Grails JAXRS-Spock plugin. Please review the new plugin's README file for installation instructions.
  • Added exclusions for un-required dependencies.
  • Modified the order of the servlet configuration; the load-on-startup field is now specified last.
  • Add the ability to specify query parameters in the test request path.
  • Take Encoding into consideration when decoding the input stream.
  • Remove copy-pasted MockHttpServletRequest from plugin.
  • Allow for multiple resources creation at once.
  • Downgraded the Grails version requirement to 2.0.x.

Version 0.8

This version enables the plugin to be used by Grails 2.2.x applications but breaks backwards compatibility for versions prior to 2.2.x.

Version 0.7

  • Enhancement: Added infrastructure to enable Spock integration testing
  • Fix: Cannot use jaxrs 0.6 with servlet 2.5 (it needs servlet api 3.0).
  • Fix: Removed usages of the deprecated Grails ConfigurationHolder.

Version 0.6

  • Upgrade to Grails 2.0.0
  • Upgrade to Jersey 1.8
  • Enhancement: Allow applications to configure init parameters for the JerseyServlet
  • Enhancement: Separate service class used by generated resources
  • Enhancement: Transaction boundaries in generated resource code
  • Enhancement: Support deep object conversion in domain object providers
  • Fix: Support for alphanumeric domain object identifiers
  • Fix: POST method doesn't work
  • Fix: java.lang.IllegalStateException: getOutputStream() has already been called for this response

Version 0.5-m1

  • New integration test framework
  • Upgrade to Grails 1.3.7
  • Upgrade to Jersey 1.5
  • Enhancement: Add support for configuring Jersey with additional provider paths
  • Enhancement: Switch to Grails' dependency management mechanism
  • Enhancement: JaxrsController moved to package org.grails.jaxrs
  • Fix: Responses with Content-Type text/html eaten by Grails
  • Fix: Service injection into resources doesn't work in integration tests

Version 0.4

  • Automated generation of WADL documents (with some known limitations)
  • Upgrade to Grails 1.3.1
  • Upgrade to Jersey 1.2
  • Upgrade to Restlet 2.0-RC3
  • Fix: Object ids in XML or JSON requests are not set on the domain object.
  • Fix: Unmarshalling from JSON (and XML) to nested domain objects doesn't work properly

There's a bug (issue 971) in Restlet 2.0-RC3 that forces implementors of MessageBodyReader and MessageBodyWriter to directly implement these interfaces. Extending a class that implements these interfaces doesn't work. Restlet will ignore the provider in this case.

Version 0.3

  • Domain object providers
    • Convert between Grails domain objects and XML or JSON representations
    • Allow usage of Grails domain classes in resource method signatures
    • Support for content negotiation using the Accept request header
    • Can be disabled by means of configuration
  • Custom entity provider support
    • Base classes for custom domain object providers
      • org.grails.jaxrs.support.DomainObjectReaderSupport
      • org.grails.jaxrs.support.DomainObjectWriterSupport
    • Base classes for more general entity providers (improved)
      • org.grails.jaxrs.support.MessageBodyReaderSupport
      • org.grails.jaxrs.support.MessageBodyWriterSupport
  • Scaffolding enhancements
    • XML and JSON representations
    • Content negotiation support
  • Auto-detection of JAX-RS resource classes better aligned with the JAX-RS specification (incl. support for annotation inheritance)
  • Auto-detection of JAX-RS provider classes better aligned with the JAX-RS specification
  • Default URL mapping for JaxrsController changed
  • Upgrade to Grails 1.1.2
  • Upgrade to Jersey 1.1.4.1
  • Upgrade to Restlet 2.0-M6

Version 0.2

In version 0.2 the way how JAX-RS resources and providers are auto-detected has changed. In version 0.1 plain Spring mechanisms were used (<context:component-scan />, Component annotation, etc.) whereas in version 0.2 the plugin follows Grails conventions regarding how to detect and manage resources. Now, there's no need to provide a custom Spring application context. The jaxrs plugin is now making these changes behind the scenes.

Similar changes have been introduced for injection of other beans into JAX-RS resources and providers. In version 0.1 plain Spring mechanisms were necessary such as the Autowired annotation whereas in version 0.2 other beans are auto-injected by name similar to Grails controllers, for example.