+

Search Tips   |   Advanced Search

Implement custom entity formats

Java API for RESTful Web Services (JAX-RS) enables developers to add a custom entity provider to the application. Use custom entity providers when we want to use Java types to represent incoming request message bodies as well as represent outgoing response message bodies. By adding a custom entity provider, we can deserialize custom Java types from message bodies and serialize any media type as message bodies.

A custom entity provider is created by annotating a class with a javax.ws.rs.ext.Provider annotation. The class must implement the javax.ws.rs.ext.MessageBodyReader interface or the javax.ws.rs.ext.MessageBodyWriter interface, or both. We must add the provider class to the list of classes returned in the javax.ws.rs.core.Application subclass getClasses() method.


Tasks

  1. Create a new Java class that is our custom entity provider. In this procedure, the example code creates a reader and a writer for com.ibm.json.java.JSONObject types so we can use the com.ibm.json.java.JSONObject type as an incoming request entity parameter and as a return type to contain the response entity.
    public class MyEntityProvider {
    
    }
    

  2. Add the @javax.ws.rs.ext.Provider annotation. Adding this annotation indicates to the JAX-RS runtime environment that this class is a JAX-RS provider. If this Provider annotation is not specified, the runtime environment does not detect that the class is a custom provider.
    @javax.ws.rs.ext.Provider
    public class MyEntityProvider {
    }
    
  3. (optional) Add a @javax.ws.rs.Consumes or @javax.ws.rs.Produces annotation to limit the media types that the entity provider supports.  In the following code snippet, the provider is only invoked when the incoming Content-Type or outgoing Content-Type is application/json.
    @javax.ws.rs.ext.Provider
    @javax.ws.rs.Consumes("application/json")
    @javax.ws.rs.Produces("application/json")
    public class MyEntityProvider {
    
    }
    
  4. Implement javax.ws.rs.ext.MessageBodyReader<T> if the entity provider needs to deserialize a message body.

    Use the generic type <T> to limit the types supported by the entity provider.

    By defining the message body reader as javax.ws.rs.ext.MessageBodyReader<com.ibm.json.java.JSONObject>, the JAX-RS runtime environment knows that only com.ibm.json.java.JSONObject objects can be produced.

    If an entity provider needs to support a complex set of types, consider implementing javax.ws.rs.ext.MessageBodyReader<Object>.

    @javax.ws.rs.ext.Provider
    @javax.ws.rs.Consumes("application/json")
    @javax.ws.rs.Produces("application/json")
    public class MyEntityProvider implements 
        javax.ws.rs.ext.MessageBodyReader<com.ibm.json.java.JSONObject> {
    
    
    
        public boolean isReadable(Class<?> type, 
                                  Type genericType, 
                                  Annotation[] annotations, 
                                  MediaType mediaType) { 
            return com.ibm.json.java.JSONObject.class == type; 
        } 
    
    
        public com.ibm.json.java.JSONObject readFrom(Class<com.ibm.json.java.JSONObject> type, 
                               Type genericType, 
                               Annotation[] annotations, 
                               MediaType mediaType, 
                               MultivaluedMap<String, String> httpHeaders, 
                               InputStream entityStream) throws IOException, WebApplicationException {
            /* This InputStream reads from the entityStream and constructs the object. */
            com.ibm.json.java.JSONObject retObj = com.ibm.json.java.JSONObject.parse(entityStream);
            return retObj; 
        } 
    
    }
    
  5. Implement javax.ws.rs.ext.MessageBodyWriter<T> if the entity provider needs to serialize a message body. We can implement the MessageBodyReader<T> and MessageBodyWriter<T> interfaces in the same Java class. In the following code snippet, only the MessageBodyWriter implementation is shown.
    @Provider 
    public class MyEntityProvider implements 
        MessageBodyWriter<Object> {
    
    
    
        public long getSize(Object t, 
                            Class<?> type, 
                            Type genericType, 
                            Annotation[] annotations, 
                            MediaType mediaType) { 
            /* return -1 if the content length cannot be determined */
    
            return -1; 
        } 
    
    
        public boolean isWriteable(Class<?> type, 
                                   Type genericType, 
                                   Annotation[] annotations, 
                                   MediaType mediaType) { 
            return MyType.class == type; 
        } 
    
    
        public void writeTo(Object t, 
                            Class<?> type, 
                            Type genericType, 
                            Annotation[] annotations, 
                            MediaType mediaType, 
                            MultivaluedMap<String, Object> httpHeaders, 
                            OutputStream entityStream) throws IOException, WebApplicationException { 
            entityStream.write(MyType.getBytes()); 
        } 
    
    }
    

  6. Add the custom entity provider to the javax.ws.rs.core.Application subclass and add the provider to the set of classes returned from the getClasses() method. We can add multiple custom entity providers to the set of classes returned.
    public class MyApplication extends javax.ws.rs.core.Application {
        public Set<Class<?>> getClasses() {
            Set<Class<?>> classes = new HashSet<Class<?>>();
            classes.add(MyEntityProvider.class);
            return classes;
        }
    }  
    

We have defined a custom entity provider and added this provider to the JAX-RS web application.

Use the following tips to resolve common errors when implementing custom entity formats:

Custom providers are not found.

To resolve this problem, take the following actions:

  • Verify that the provider is annotated with a @javax.ws.rs.ext.Provider. A class missing the annotation is not registered as a provider.

  • Verify that the provider is added to the set of classes returned from the getClasses() method for the subclasses of the javax.ws.rs.core.Application class.

  • Verify that the @javax.ws.rs.Produces or @javax.ws.rs.Consumes value on the provider class is correct.

  • Verify that the javax.ws.rs.ext.MessageBodyReader#isReadable method or the javax.ws.rs.ext.MessageBodyWriter#isWritable method is implemented correctly and they correctly return a value of true when these methods are used.

Custom essageBodyWriter entity provider headers or output is not correct.

To resolve this problem, take the following actions:

  • Verify that the size of the response in javax.ws.rs.ext.MessageBodyWriter#getSize is either set to -1 if the size is unknown, or the value is set to the correct size when the size is known. Clients might truncate the response if the size value is inaccurate.

  • If HTTP headers are set in the javax.ws.rs.ext.MessageBodyWriter#writeTo method, set the headers before the rest of the HTTP response is sent. HTTP headers are sent at the beginning of a response. Therefore, if we set the headers after the main response message body has started being sent to the client, then it is too late to send response headers.

  • Use custom entity formats
  • Web services specifications and APIs