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.
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 ajava.util.Map
. This map can be used for constructing domain objects.org.grails.jaxrs.provider.XMLWriter
converts angrails.converters.XML
object into an XML representation.
import grails.converters.XMLclass 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 ajava.util.Map
. This map can be used for constructing domain objects.org.grails.jaxrs.provider.JSONWriter
converts angrails.converters.JSON
object into a JSON representation.
import grails.converters.JSONclass 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 thegrails-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 implementsjavax.ws.rs.ext.MessageBodyReader
. - must have a file name matching
*Writer.groovy
if the corresponding class implementsjavax.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
Person
domain class (see
scaffolding example), for all other classes the default XML creation should occur. Here's the custom
provider.package helloimport 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) } } }
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>
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>
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>
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 … } } }
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)) } }
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.