The Java EE 7 Tutorial

Previous
Next

31.6 Runtime Content Negotiation

The @Produces and @Consumes annotations handle static content negotiation in JAX-RS. These annotations specify the content preferences of the server. HTTP headers such as Accept, Content-Type, and Accept-Language define the content negotiation preferences of the client.

For more details on the HTTP headers for content negotiation, see HTTP /1.1 - Content Negotiation (http://www.w3.org/Protocols/rfc2616/rfc2616-sec12.html).

The following code snippet shows the server content preferences:

@Produces("text/plain")
@Path("/employee")
public class Employee {

    @GET
    public String getEmployeeAddressText(String address) {...}

    @Produces("text/xml")
    @GET
    public String getEmployeeAddressXml(Address address) {...}
}

The getEmployeeAddressText method is called for an HTTP request that looks like the following:

GET /employee
Accept: text/plain

This will produce the following response:

500 Oracle Parkway, Redwood Shores, CA

The getEmployeeAddressXml method is called for an HTTP request that looks like the following:

GET /employee
Accept: text/xml

This will produce the following response:

<address street="500 Oracle Parkway, Redwood Shores, CA" country="USA"/>

With static content negotiation, you can also define multiple content and media types for the client and server.

@Produces("text/plain", "text/xml")

In addition to supporting static content negotiation, JAX-RS also supports runtime content negotiation using the javax.ws.rs.core.Variant class and Request objects. The Variant class specifies the resource representation of content negotiation. Each instance of the Variant class may contain a media type, a language, and an encoding. The Variant object defines the resource representation that is supported by the server. The Variant.VariantListBuilder class is used to build a list of representation variants.

The following code snippet shows how to create a list of resource representation variants:

List<Variant> vs = Variant.mediatypes("application/xml", "application/json")
        .languages("en", "fr").build();

This code snippet calls the build method of the VariantListBuilder class. The VariantListBuilder class is invoked when you call the mediatypes, languages, or encodings methods. The build method builds a series of resource representations. The Variant list created by the build method has all possible combinations of items specified in the mediatypes, languages, and encodings methods.

In this example, the size of the vs object as defined in this code snippet is 4, and the contents are as follows:

[["application/xml","en"], ["application/json","en"],
    ["application/xml","fr"],["application/json","fr"]]

The javax.ws.rs.core.Request.selectVariant method accepts a list of Variant objects and chooses the Variant object that matches the HTTP request. This method compares its list of Variant objects with the Accept, Accept-Encoding, Accept-Language, and Accept-Charset headers of the HTTP request.

The following code snippet shows how to use the selectVariant method to select the most acceptable Variant from the values in the client request:

@GET
public Response get(@Context Request r) { 
    List<Variant> vs = ...;
    Variant v = r.selectVariant(vs);
    if (v == null) {
        return Response.notAcceptable(vs).build();
    } else {
        Object rep = selectRepresentation(v);
        return Response.ok(rep, v);
    }
}

The selectVariant method returns the Variant object that matches the request or null if no matches are found. In this code snippet, if the method returns null, a Response object for a nonacceptable response is built. Otherwise, a Response object with an OK status and containing a representation in the form of an Object entity and a Variant is returned.

Previous
Next