(Quick Reference)

5 Entity Providers

Version: 3.1.0

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.