Pluggable types with JAX-RS and Jersey

JAX-RS and Jersey support a pluggable type system for the encoding/decoding of a Java type to/from an entity of an HTTP response/request.

JAX-RS specifies a number of Java types to be supported by an implementation, such as String, InputStream and JAXB beans. Jersey provides implementations for those types in addition to further types, such as support for Atom (using the ROME library), and just recently Jakub added support for JSON (using JSONArray, JSONObject and using the BadgerFish convention supported by Jettison for encoding/decoding JAXB beans to/from JSON).

You can find all the implementations in the com.sun.ws.rest.impl.provider.entity package. They all implement the EntityProvider interface and are registered in the META-INF/services file javax.ws.rs.ext.EntityProvider.

It is reasonably easy to write your own implementation of EntityProvider that supports additional Java types to those supported by JAX-RS and Jersey. An example I recently added to Jersey shows how this can be achieved for encoding/decoding instances of java.util.Properties, and the implementation is as follows:

public class PropertiesProvider implements EntityProvider<Properties> {
   
    public boolean supports(Class<?> type) {
        // Only support the Properties classe and inherited classes of
        return Properties.class.isAssignableFrom(type);
    }
       
    public Properties readFrom(Class<Properties> type, String mediaType,
            MultivaluedMap<String, String> headers, InputStream in)

throws IOException {
        // Create a new Properties instance and load using the
        // key/value pair format
        Properties p = new Properties();
        p.load(in);
        return p;
    }
   
    public void writeTo(Properties p,
            MultivaluedMap<String, Object> headers, OutputStream out)

throws IOException {
        // Store the Properties instance using the key/value pair format
        p.store(out, null);
    }
}

Notice that the PropertiesProvider.supports method only returns true if the type parameter can be assigned to java.util.Properties. The Jersey runtime when encoding or decoding a Java type will iterate through the list of registered EntityProvider and utilize the first EntityProvider that supports the Java type.

The PropertiesProvider class is registered in the META-INF/services file javax.ws.rs.ext.EntityProvider the contents of which are:

com.sun.ws.rest.samples.entityprovider.PropertiesProvider

That is it. Reasonably simple, although the use of the META-INF/services file is not so obvious and we need to improve on this by enabling tooling to do the registration (the hooks are in place and it needs to be implemented), perhaps using a similar mechanism to that in HK2.

Once the PropertiesProvider is implemented and registered a Java resource can be written that utilizes java.util.Properties:

@UriTemplate("/properties")
@ProduceMime("text/plain")
public class PropertiesResource {

    // Get the current system properties of the JVM
    @HttpMethod
    public Properties getSystemProperties() {
        return System.getProperties();
    }

    // Reflect POSTed properties
    @HttpMethod("POST")
    @ConsumeMime("text/plain")
    public Properties reflectProperties(Properties p) {
        return p;
    }
}

 

The method getSystemProperties will reply with list of JVM system properties when a client issues a GET request to the Properties resource. The PropertiesProvider will manage the encoding of the Properties instance to textual key/value pairs.

The method reflectProperties will reply with the same properties that are POSTed to the Properties resource. The PropertiesProvider will manage the decoding of the Properties parameter p.

 

Comments:

Post a Comment:
  • HTML Syntax: NOT allowed
About

sandoz

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today