JAX-RS defines Entity Providers that supply mapping services between on-the-wire representations and their associated Java types. The entities, also known as "message payload" or "payload" represent the main part of an HTTP message. These are specified as method parameters and return types of resource methods. Several standard Java types such as
String
, byte[]
, javax.xml.bind.JAXBElement
,java.io.InputStream
, java.io.File
, and
others have a pre-defined mapping and is required by the
specification. Applications may provide their own mapping to custom
types using MessageBodyReader
and MessageBody
Writer
interfaces. This allows to extend the JAX-RS runtime easily to
support your own custom entity providers.The
MessageBodyReader
interface defines the contract
for a provider that supports the conversion of a stream to a Java
type. The MessageBodyWriter
interface defines the
contract for a provider that supports the conversion of a Java type
to a stream. This Tip Of The Day
(TOTD) will explain how to write these custom entity providers.Note, this functionality was defined in JAX-RS 1.0 as opposed to Client API, Client- and Server-side async, Hypermedia, and many other features. The complete source code for this sample application can be downloaded here and will work on GlassFish 4.0 b70.
Here is a simple resource that returns name of the fruit based upon the
index
passed as parameter:@Path("fruits")This resource can be invoked using the newly introduced Client API as:
public class MyResource {
private String[] response = { "apple", "banana", "mango" };
@POST
public String getFruit(int index) {
return response[index % 3];
}
}
Client client = ClientFactory.newClient();
WebTarget target = client.target("http://"
+ request.getServerName()
+ ":"
+ request.getServerPort()
+ request.getContextPath()
+ "/webresources/fruits");
String fruit = target
.request()
.post(Entity.text("1"), String.class);
If we update the resource such that the
index
parameter is passed as the following object:public class MyObject implements Serializable {Then the resource method would look like:
public static final String MIME_TYPE = "application/myType";
private int index;
public MyObject() {
}
public MyObject(int index) {
this.index = index;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
}
@POST
@Consumes(value=MyObject.MIME_TYPE)
public String getFruit(MyObject mo) {
return response[Integer.valueOf(mo.getIndex()) % 3];
}
The additional
@Consumes
annotation defines the media
type that the method can accept. The following custom entity
providers are defined to support this custom type. The first one, MyReader
,
defines the conversion of on-the-wire representation to MyObject
Java type.@ProviderThe interface require two methods,
@Consumes(MyObject.MIME_TYPE)
public class MyReader implements MessageBodyReader<MyObject> {
@Override
public boolean isReadable(Class<?> type, Type type1, Annotation[] antns, MediaType mt) {
return MyObject.class.isAssignableFrom(type);
}
@Override
public MyObject readFrom(Class<MyObject> type,
Type type1,
Annotation[] antns,
MediaType mt, MultivaluedMap<String, String> mm,
InputStream in) throws IOException, WebApplicationException {
try {
ObjectInputStream ois = new ObjectInputStream(in);
return (MyObject)ois.readObject();
} catch (ClassNotFoundException ex) {
Logger.getLogger(MyReader.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
}
isReadable
and readFrom
,
to be implemented. The implementation has @Consumes
annotation restricting the media type supported by this entity
provider.The second one,
MyWriter
, defines the conversion fromMyObject
Java type to on-the-wire representation.@ProviderThe interface require three methods
@Produces(MyObject.MIME_TYPE)
public class MyWriter implements MessageBodyWriter<MyObject> {
@Override
public boolean isWriteable(Class<?> type, Type type1, Annotation[] antns, MediaType mt) {
return MyObject.class.isAssignableFrom(type);
}
@Override
public long getSize(MyObject t, Class<?> type, Type type1, Annotation[] antns, MediaType mt) {
// As of JAX-RS 2.0, the method has been deprecated and the
// value returned by the method is ignored by a JAX-RS runtime.
// All MessageBodyWriter implementations are advised to return -1 from
// the method.
return -1;
}
@Override
public void writeTo(MyObject t,
Class<?> type,
Type type1,
Annotation[] antns,
MediaType mt,
MultivaluedMap<String, Object> mm,
OutputStream out) throws IOException, WebApplicationException {
ObjectOutputStream oos = new ObjectOutputStream(out);
oos.writeObject(t);
}
}
isWriteable
, getSize
,writeTo
to be implemented. The implementation of
getSize method is recommended to return -1 as JAX-RS runtime is
required to compute the actual Content-Length
header
value. The implementation has @Produces
annotation
restricting the media type supported by this entity provider.The reader and writer entity providers are marked with
@Provider
and are thus automatically discovered at runtime on the server-side.
But until JERSEY-1634
is fixed, they need to be explicitly specified in the Application
class as:@ApplicationPath("webresources")
public class MyApplication extends Application {
@Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources = new java.util.HashSet<>();
resources.add(MyResource.class);
resources.add(MyReader.class);
resources.add(MyWriter.class);
return resources;
}
}
On the client-side, the providers need to be explicitly registered as shown:
Client client = ClientFactory.newClient();Notice, how invoking the endpoint requires to specify the media type as part of
client
.configuration()
.register(MyReader.class)
.register(MyWriter.class);
String fruit = target
.request()
.post(Entity.entity(new MyObject(1), MyObject.MIME_TYPE), String.class);
post
method invocation.The complete source code for this sample application can be downloaded here and will work on GlassFish 4.0 b70.
Here are some more pointers to follow
- JAX-RS 2 Specification Public Review
- Latest status on
specification (jax-rs-spec.java.net)
- Latest JAX-RS 2.0 Javadocs
- Latest status on Jersey (Reference Implementation of JAX-RS 2 - jersey.java.net)
- Latest Jersey API Javadocs
- Latest
GlassFish
4.0 Promoted Build
- Follow @gf_jersey
Provide feedback on Jersey 2 to users@jersey.java.net
and JAX-RS specification to users@jax-rs-spec.java.net.