The JAX-RS framework uses MessageBodyWriter to serialize the Java representation of resources returned by the REST web API into an appropriate format, which is sent back to the client. The JAX-RS runtime natively supports the serialization of the commonly used Java types, such as java.lang.String, java.io.InputStream, and Java custom objects annotated with JAXB binding annotations. You can provide your own implementation of MessageBodyWriter if you find that the default implementation provided by JAX-RS is not meeting your use case requirements.
A javax.ws.rs.ext.MessageBodyWriter<T> provider should implement the following methods:
- isWriteable(): This method checks whether this MessageBodyWriter implementation supports converting the Java type present in the method argument to the designated internet media type. This method is invoked when the framework tries to find a MessageBodyWriter implementation for serializing the Java objects returned by a resource method to the designated internet media type.
- getSize(): JAX-RS 2.0 deprecated this method, and the value returned by the method is ignored by the JAX-RS runtime. You can return -1 from this method.
- writeTo(): This method writes a Java type object to an HTTP message.
Keep a note of the following points when building a MessageBodyWriter implementation:
- A MessageBodyWriter provider implementation may be annotated with @Produces to restrict the media types for which it will be considered suitable
- A MessageBodyWriter provider implementation must be either programmatically registered in the JAX-RS runtime or must be annotated with @Provider annotation
The following example shows how you can build a custom MessageBodyWriter implementation that converts a list of the Department Java objects into the CSV format:
//Other imports omitted for brevity import javax.ws.rs.Produces; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.ext.MessageBodyWriter; import javax.ws.rs.ext.Provider; import org.supercsv.io.CsvBeanWriter; import org.supercsv.io.ICsvBeanWriter; import org.supercsv.prefs.CsvPreference; @Provider @Produces("application/csv") public class CSVMessageBodyWriter implements MessageBodyWriter<List<Department>> { /** * Ascertain if MessageBodyWriter supports * a particular type. */ @Override public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { //Is this MessageBodyWriter implementation capable //of serializing the object type returned by //the current REST API call? return (List.class.isAssignableFrom(type)); } /** *Deprecated by JAX-RS 2.0 and ignored by Jersey runtime */ @Override public long getSize(List<Department> t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { return 0; } /** * Converts Java to desired media type and Writes it * to an HTTP response */ @Override public void writeTo(List<Department> dataList, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException { // This class uses CsvBeanWriter for converting // Java to CSV. It is an open source framework // that writes a CSV file by mapping each field // on the bean to a column in the CSV file //(using the supplied name mapping). ICsvBeanWriter writer = new CsvBeanWriter( new PrintWriter(entityStream), CsvPreference.STANDARD_PREFERENCE); //No data then return if (dataList == null || dataList.size() == 0) { return; } //Columns headers in CSV String[] nameMapping ={"departmentId","departmentName", "managerId","locationId"} ; //CsvBeanWriter writes the header with the property names writer.writeHeader(nameMapping); for (Object p : dataList) { //Write each row writer.write(p, nameMapping); } writer.close(); } }
The following RESTful web service call illustrates a sample output (in CSV format) generated by the CSVMessageBodyWriter implementation:
GET /api/hr/departments HTTP/1.1 Host: localhost:8080 Accept: application/csv departmentId,departmentName,locationId,managerId 1001,"Finance",1700,101 1002,"Office Administration",1500,205