Zach's Blog

Just another WordPress.com weblog

Posts Tagged ‘jersey

Jersey + Guice + Scala

with 6 comments

At Pongr, our RESTful web services are built using Jersey, Guice and Scala (among many other technologies). Here’s a quick post that shows how to set up an example project that uses all three. By the end we’ll be able to declare Guice bindings in our own custom module and have them injected into Jersey resource classes.

We’ll manage everything with Maven, so first create your pom.xml. I know it looks like a lot, but only has three Jersey dependencies (and one on the Servlet 2.5 API to make things compile). The rest of this junk is mainly configuring plugins for Scala – don’t worry about it. The upshot is that you can a) run this all using mvn jetty:run, and b) can generate an Eclipse project using mvn eclipse:eclipse.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.pongr</groupId>
    <artifactId>jerseyguicescala</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>jerseyguicescala</name>
    <properties>
        <jersey-version>1.1.1-ea</jersey-version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-server</artifactId>
            <version>${jersey-version}</version>
        </dependency>
        <dependency>
            <groupId>com.sun.jersey.contribs</groupId>
            <artifactId>jersey-guice</artifactId>
            <version>${jersey-version}</version>
        </dependency>
        <dependency>
            <groupId>com.sun.jersey.contribs</groupId>
            <artifactId>jersey-scala</artifactId>
            <version>${jersey-version}</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <!-- Run with "mvn jetty:run" -->
            <plugin>
                <groupId>org.mortbay.jetty</groupId>
                <artifactId>maven-jetty-plugin</artifactId>
                <version>6.1.19</version>
                <configuration>
                    <contextPath>/</contextPath>
                </configuration>
            </plugin>
            <!-- Begin scala plugins, inspired by: http://scala-tools.org/mvnsites/maven-scala-plugin/usage_java.html -->
            <plugin>
                <groupId>org.scala-tools</groupId>
                <artifactId>maven-scala-plugin</artifactId>
                <executions>
                    <execution>
                        <id>scala-compile-first</id>
                        <phase>process-resources</phase>
                        <goals>
                            <goal>add-source</goal>
                            <goal>compile</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>scala-test-compile</id>
                        <phase>process-test-resources</phase>
                        <goals>
                            <goal>testCompile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
                <executions>
                    <execution>
                        <phase>compile</phase>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <artifactId>maven-eclipse-plugin</artifactId>
                <configuration>
                    <sourceIncludes>
                        <sourceInclude>**/*.scala</sourceInclude>
                    </sourceIncludes>
                    <buildcommands>
                        <buildcommand>ch.epfl.lamp.sdt.core.scalabuilder</buildcommand>
                    </buildcommands>
                    <additionalProjectnatures>
                        <!-- This nature gets put after org.eclipse.jdt.core.javanature in .project so Eclipse has a J badge on the project instead of an S -->
                        <projectnature>ch.epfl.lamp.sdt.core.scalanature</projectnature>
                    </additionalProjectnatures>
                    <classpathContainers>
                        <classpathContainer>org.eclipse.jdt.launching.JRE_CONTAINER</classpathContainer>
                        <classpathContainer>ch.epfl.lamp.sdt.launching.SCALA_CONTAINER</classpathContainer>
                    </classpathContainers>
                </configuration>
            </plugin>
            <!-- http://groups.google.com/group/liftweb/browse_thread/thread/3dac7002f9e59546/3918bba2f7a92cd3?pli=1 -->
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>build-helper-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <id>add-source</id>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>add-source</goal>
                        </goals>
                        <configuration>
                            <sources>
                                <source>src/main/scala</source>
                            </sources>
                        </configuration>
                    </execution>
                    <execution>
                        <id>add-test-source</id>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>add-test-source</goal>
                        </goals>
                        <configuration>
                            <sources>
                                <source>src/test/scala</source>
                            </sources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <!-- End scala plugins -->
        </plugins>
    </build>
</project>

Next up, create the src/main/webapp/WEB-INF/web.xml file. This just registers our special GuiceConfig class that, uh, configures Guice.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_5.xsd" metadata-complete="false" version="2.5">
    <listener>
        <listener-class>com.pongr.GuiceConfig</listener-class>
    </listener>
    <filter>
        <filter-name>guiceFilter</filter-name>
        <filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>guiceFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

We’ll create an example Guice module in the src/main/java/com/pongr/ExampleModule.java file. It just binds a message String that we’ll inject into our resource classes later.

package com.pongr;

import com.google.inject.*;
import com.google.inject.name.*;

public class ExampleModule extends AbstractModule
{
    @Override
    protected void configure()
    {
        bindConstant().annotatedWith(Names.named("message")).to("Hello, World!");
    }
}

Next up is src/main/java/com/pongr/GuiceConfig.java where we connect Jersey to Guice. This is where we create the Guice Injector using our ExampleModule and configure any Jersey properties, like the package(s) that contain our resource classes.

package com.pongr;

import java.util.*;

import com.google.inject.*;
import com.google.inject.servlet.*;
import com.sun.jersey.api.core.*;
import com.sun.jersey.guice.spi.container.servlet.*;

public class GuiceConfig extends GuiceServletContextListener
{
    @Override
    protected Injector getInjector()
    {
        final Map<String, String> params = new HashMap<String, String>();
        params.put(PackagesResourceConfig.PROPERTY_PACKAGES, "com.pongr");
        return Guice.createInjector(new ExampleModule(), new ServletModule()
        {
            @Override
            protected void configureServlets()
            {
                serve("/*").with(GuiceContainer.class, params);
            }
        });
    }
}

Now for the fun! This src/main/java/com/pongr/JavaResource.java file gets the message String injected and displays it.

package com.pongr;

import javax.ws.rs.*;
import javax.ws.rs.core.*;

import com.google.inject.*;
import com.google.inject.name.*;

@Path("java")
public class JavaResource
{
    private String message;

    @Inject
    public JavaResource(@Named("message") String message)
    {
        this.message = message;
    }

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String get()
    {
        return "From Java: " + message;
    }
}

And for good measure here’s src/main/scala/com/pongr/ScalaResource.scala. Same as JavaResource, except in Scala. The Guice @Inject and @Named annotations can be a bit tricky for constructor injection, so here’s how it’s done.

package com.pongr

import javax.ws.rs._
import javax.ws.rs.core._

import com.google.inject._
import com.google.inject.name._

@Path("scala")
class ScalaResource @Inject() (@Named("message") message: String) {
  @GET
  @Produces(Array(MediaType.TEXT_PLAIN))
  def get(): String = "From Scala: " + message
}

That’s it! Now just run mvn jetty:run on your command line and hit http://localhost:8080/java and http://localhost:8080/scala in your browser to see these resources in action. As always, you can also visit http://localhost:8080/application.wadl to get an overview of the available resources. Enjoy!

Written by Zach Cox

September 22, 2009 at 10:03 pm

Posted in Java, Scala

Tagged with , , , ,

Dynamically Generating Zip Files in Jersey

with one comment

We often need to pull a large number of rows from a database table, split those rows up into n groups, and write each group out to a separate text file.  These text files are then processed by another application.  Each text file starts with the number of rows in the file on the first line, and then contains each row on its own line after that.  It became a pain to generate these files by hand, so I added a new resource to our Jersey-based web service that would generate all of the files and wrap them all up into a single .zip file.  The processing app also used to be run by hand, but it’s now totally automated, so it obtains the .zip file, unzips it, and processes each individual file.

Here is the resource we ended up with, except for this blog I’m just generating a list of 100 random strings instead of pulling rows from a real database:

import java.io.*;
import java.util.*;
import java.util.zip.*;

import javax.ws.rs.*;

@Path("/files")
public class FilesResource
{
    @GET
    @Produces("application/x-zip-compressed")
    public InputStream getZipFile(@QueryParam("per_file") @DefaultValue("25") final int perFile)
            throws IOException
    {
        //we write to the PipedOutputStream
        //that data is then available in the PipedInputStream which we return
        final PipedOutputStream sink = new PipedOutputStream();
        PipedInputStream source = new PipedInputStream(sink);

        //apparently we need to write to the PipedOutputStream in a separate thread
        Runnable runnable = new Runnable()
        {
            public void run()
            {
                //PrintStream => BufferedOutputStream => ZipOutputStream => PipedOutputStream
                ZipOutputStream zip = new ZipOutputStream(sink);
                PrintStream writer = new PrintStream(new BufferedOutputStream(zip));

                try
                {
                    //break the strings up into multiple files
                    List<String> strings = getStrings();
                    int stringCount = strings.size();
                    int fileCount = (int) Math.ceil((double) stringCount / (double) perFile);
                    for (int file = 0; file < fileCount; file++)
                    {
                        zip.putNextEntry(new ZipEntry("file" + (file + 1) + ".txt"));
                        int first = file * perFile;
                        int last = Math.min((file + 1) * perFile, stringCount);
                        int imagesInFile = last - first;
                        writer.println(imagesInFile);
                        for (int i = first; i < last; i++)
                            writer.println(strings.get(i));
                        writer.flush();
                        zip.closeEntry();
                    }

                    //also include a single file with all strings
                    writer.println(stringCount);
                    zip.putNextEntry(new ZipEntry("file.txt"));
                    for (int i = 0; i < stringCount; i++)
                        writer.println(strings.get(i));
                    writer.flush();
                    zip.closeEntry();
                }
                catch (IOException e)
                {
                }
                writer.flush();
                writer.close();
            }
        };
        Thread writerThread = new Thread(runnable, "FileGenerator");
        writerThread.start();

        return source;
    }

    private List<String> getStrings()
    {
        List<String> strings = new ArrayList<String>();
        for (int i = 0; i < 100; i++)
            strings.add(String.valueOf(Math.random()));
        return strings;
    }
}

The getZipFile() method will be called in response to a GET /files request.  I also registered the .zip URI extension so it will also respond to GET /files.zip.  By default it will split up the strings into groups of 25, but the per_file query parameter can be specified in the request to change that, like GET /files.zip?per_file=50 to split them into groups of 50.

The easiest way to create a .zip file in Java is using ZipOutputStream.  Once you have that created you call its putNextEntry() method to start a new file within the .zip file.  We also wrapped the ZipOutputStream in a PrintStream, and write the contents of the text files by calling println() on the PrintStream (there’s also a BufferedOutputStream in there for good measure).

Jersey is smart enough to read the data from an InputStream and use it as the HTTP response body, so ultimately we need to return an InputStream.  By hooking the ZipOutputStream up to a PipedOutputStream, and then connecting the PipedOutputStream to a PipedInputStream, Jersey can read this all of this zip file data from the PipedInputStream.  It’s best to write-to and read-from these piped streams in different threads so we start a new writing thread and return the PipedInputStream right away.

This ends up working perfectly: the resource at http://site.com/files.zip feels like a static zip file, but is really generated dynamically on every request.  It also can now be accessed overy HTTP from any machine and processed automatically.  If it was really expensive to generate we could cache it and re-generate only when one of the rows in the database changed, but for our purposes it’s a cheap .zip file to generate.

Written by Zach Cox

August 26, 2009 at 7:43 am

Posted in Java

Tagged with ,

URI Extensions in Jersey

with 2 comments

Jersey provides an excellent system for easily supporting multiple representations of resources. You use the @Produces annotation to define which formats a resource method supports:

@GET
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Thing getThing()
{
    Thing thing = ...;
    return thing;
}

In this case clients can obtain the representation of the thing resource in either XML or JSON format (assuming you’ve registered corresponding MessageBodyWriters for the Thing class).  Just by including the @Produces annotation, Jersey handles sending the response back in the proper format and will even send a 415 Unsupported Media Type response automatically if the client requests the resource in an unsupported format.

By default Jersey uses the Accept request header to determine which response format to use.  Setting request headers in client apps can be cumbersome though, so a more convenient approach is to use URI extensions.  So if you want the http://site.com/thing resource as XML you GET http://site.com/thing.xml, or GET http://site.com/thing.json if you want its JSON representation.

To tell Jersey to use URI extensions, you create a cusom PackagesResourceConfig implementation and set up the mappings between extensions and media types:

import java.util.*;
import javax.ws.rs.core.*;
import com.sun.jersey.api.core.*;

/** Registers URI extensions for some common media types.  This lets clients specify the desired 
 * response format right in the URI like http://site.com/whatever.xml instead of 
 * http://site.com/whatever with an Accept:application/xml header. */
public class UriExtensionsConfig extends PackagesResourceConfig
{
    private Map<String, MediaType> mediaTypeMap;

    public UriExtensionsConfig()
    {
        super();
    }

    public UriExtensionsConfig(Map<String, Object> props)
    {
        super(props);
    }

    public UriExtensionsConfig(String[] paths)
    {
        super(paths);
    }

    @Override
    public Map<String, MediaType> getMediaTypeMappings()
    {
        if (mediaTypeMap == null)
        {
            mediaTypeMap = new HashMap<String, MediaType>();
            mediaTypeMap.put("json", MediaType.APPLICATION_JSON_TYPE);
            mediaTypeMap.put("xml", MediaType.APPLICATION_XML_TYPE);
            mediaTypeMap.put("txt", MediaType.TEXT_PLAIN_TYPE);
            mediaTypeMap.put("html", MediaType.TEXT_HTML_TYPE);
            mediaTypeMap.put("xhtml", MediaType.APPLICATION_XHTML_XML_TYPE);
            MediaType jpeg = new MediaType("image", "jpeg");
            mediaTypeMap.put("jpg", jpeg);
            mediaTypeMap.put("jpeg", jpeg);
            mediaTypeMap.put("zip", new MediaType("application", "x-zip-compressed"));
        }
        return mediaTypeMap;
    }
}

You register the UriExtensionsConfig in web.xml like this:

    <servlet>
        ...
        <init-param>
            <param-name>com.sun.jersey.config.property.resourceConfigClass</param-name>
            <param-value>com.pongr.rest.config.UriExtensionsConfig</param-value>
        </init-param>
    </servlet>

This provides yet another way to make your web services more user-friendly. Clients can still use the Accept header but can also use standard URI extensions to specify the desired response format.

Written by Zach Cox

August 11, 2009 at 4:40 pm

Posted in Java

Tagged with , , , ,

XHTML Resource Representations in Jersey using StringTemplate

leave a comment »

Most web services these days use XML and/or JSON as representation formats, mainly because they are simple to create and are easily parseable by other apps.  A less commonly used, but extremely useful format is XHTML.  But wait, that’s for displaying web pages right?  It sure is, but it’s also valid XML.  So if you use XHTML as a representation format, your responses are both viewable to a human in a web browser and parseable by a machine.

Being viewable in a browser is a great way to make your web service self-documenting.  If you use XHTML, instead of reading boring documentation about your web service or using curl to get real XML/JSON responses your users can just navigate around your service using their favorite browser.  The pages look nice so it’s easy to see what information is available for each resource, and they can view the page source to see how to parse it.  XHTML makes linking to other resources easy using the <a> element (remember: hypermedia as the engine of application state!).  XHTML also lets you build forms to show how to use other resources: the forms are easily usable by humans and they also show which HTTP method and parameters to use when making requests from your own app.

While you can use a tool like XStream to serialize your Java objects to XML or JSON, using XHTML will generally require hand-crafting the responses.  What you don’t want to do is build up the entire response in Java:

@GET
@Produces(MediaType.APPLICATION_XHTML_XML)
public String getUser()
{
    User user = ...;
    return "<html><body><dl><dt>First name:</dt><dd>" + user.getFirstName() +
        "</dd><dt>Last name:</dt><dd>" + user.getLastName() +
        "</dd><dt>Email:</dt><dd>" + user.getEmail() +
        "</dd></dl></body></html>";
}

That looks terrible and is going to be very hard to maintain.

What you really need to do is use some sort of template engine.  This will let you put the overall response into a plain text file with certain markers where the data will go.  I’ve found StringTemplate to be one of the best template engines.  You can read all about its great virtues on its own site, but the main idea is that there is basically no logic in the view templates.

To refactor the previous example using StringTemplate, we’d first create a User.st file:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
  <head>
    <title>User $user.ID$</title>
  </head>
  <body>
    <dl>
      <dt>First name:</dt> <dd id="firstName">$user.firstName$</dd>
      <dt>Last name:</dt> <dd id="lastName">$user.lastName$</dd>
      <dt>Email:</dt> <dd id="email">$user.email$</dd>
    </dl>
  </body>
</html>

This defines the overall structure of our template, providing places where the user data will get inserted.  Anything between the dollar signs is a StringTemplate expression that the engine evaluates.  So $user.firstName$ results in the getFirstName() method being called on our User object.

Then we would bind a User object to the User.st template and render it:

@GET
@Produces(MediaType.APPLICATION_XHTML_XML)
public String getUser()
{
    User user = ...;
    StringTemplateGroup group = new StringTemplateGroup("someGroup");
    StringTemplate template = group.getInstanceOf("path/to/User");
    template.setAttribute("user", user);
    return template.toString();
}

And this is what will get sent back in the response body:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
  <head>
    <title>User 1234</title>
  </head>
  <body>
    <dl>
      <dt>First name:</dt> <dd id="firstName">Zach</dd>
      <dt>Last name:</dt> <dd id="lastName">Cox</dd>
      <dt>Email:</dt> <dd id="email">zach@something.com</dd>
    </dl>
  </body>
</html>

As you can see, this is just XHTML and is easily parseable.  To extract the first name, you could use an XPath expression like “//dd[@id='firstName']“.  If you view this response in a browser, it’s very easy to quickly see what information this resource provides:

User Template

We could also include links to other resources (maybe the user has a set of recipes at /user/{username}/recipes) or a simple form to change the user’s info (it would do a POST to /users/{username} and have a hidden _method=PUT field to account for browsers not support the PUT request).

Written by Zach Cox

June 26, 2009 at 11:24 am

Posted in Java

Tagged with , ,

Use Exceptions to Send Error Responses in Jersey

with one comment

Jersey provides several different ways to send back particular HTTP responses.  While your resource methods can all return Response objects, sometimes it’s more natural to return a domain object if everything goes OK and throw exceptions when errors occur.

The WebApplicationException class serves this purpose.  You throw an instance of it in your resource method, Jersey catches it and sends back the corresponding HTTP response.  While it’s perfectly fine to create & throw WebApplicationException objects, it’s a lot more convenient to create your own subclasses of it for commonly-used responses.

401 Unauthorized

If you have an authentication/authorization system in place to protect access to certain resources, you will become very familiar with the 401 response.  Let’s say we have an Authentication interface and an instance of it can be injected into a resource class:

public interface Authentication
{
    public boolean isAuthenticated(String authorization);
}

One of the first things you’d want to do in a protected resource method is check the user’s credentials, and return a 401 response if necessary:

//this gets injected somehow
private Authentication auth;

@GET
public ImportantThing getImportantThing(@HeaderParam(HttpHeaders.AUTHORIZATION) String authorization)
{
    if (!auth.isAuthenticated(authorization))
        throw new UnauthorizedException();

    ImportantThing thing = ...;
    return thing;
}

This code is very simple and gets the point across to other developers: the method is normally supposed to return an ImportantThing, but in the error case where a user is not properly authorized, an exception is thrown.

Here’s what I use for UnauthorizedException:

import javax.ws.rs.*;
import javax.ws.rs.core.*;
import javax.ws.rs.core.Response.*;

/** Throw this exception to return a 401 Unauthorized response.  The WWW-Authenticate header is
 * set appropriately and a short message is included in the response entity. */
public class UnauthorizedException extends WebApplicationException
{
    private static final long serialVersionUID = 1L;

    public UnauthorizedException()
    {
        this("Please authenticate.", "Name of your web service");
    }

    public UnauthorizedException(String message, String realm)
    {
        super(Response.status(Status.UNAUTHORIZED).header(HttpHeaders.WWW_AUTHENTICATE,
                                                          "Basic realm=\"" + realm + "\"")
                .entity(message).build());
    }
}

409 Conflict

Let’s say in your web service you have a user account resource with URI /users/{username}.  When creating or updating a user by doing a PUT /users/{username} you need to prevent duplicate usernames.  This is a perfect opportunity to return a 409 response.

@PUT
@Path("{username}")
public User createOrUpdateUser(@PathParam("username") String username, @Context UriInfo uriInfo)
{
    if (usernameExists(username))
        throw new ConflictException(uriInfo.getBaseUriBuilder().path("/users/{username}").build(username));

    //create or update the user
    return user;
}

Pretty simple: detect a potential resource conflict and throw an exception.  As a best practice we also include the URI of the conflicting resource in the response.

import java.net.*;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
import javax.ws.rs.core.Response.*;

/** Thrown to return a 409 Conflict response with optional Location header and entity. */
public class ConflictException extends WebApplicationException
{
    private static final long serialVersionUID = 1L;

    public ConflictException()
    {
        this(null, null);
    }

    public ConflictException(URI location)
    {
        this(location, null);
    }

    public ConflictException(URI location, Object entity)
    {
        super(Response.status(Status.CONFLICT).location(location).entity(entity).build());
    }
}

400 Bad Request

The 400 response is the generic client-side error response.  I typically use it when there are validation errors in parameters submitted to the web service, when creating or updating a resource.  It’s useful to include the error messages in the response body instead of just sending the 400 response.

Let’s continue the user account example.  When creating/updating a user we need to validate a couple things:

  • Email address is properly formed
  • A name is provided

We’ll perform all of the validations and send back a 400 response if any of them fail:

@PUT
@Path("{username}")
public User createOrUpdateUser(@PathParam("username") String username, @FormParam("email") String email, @FormParam("name") String name, @Context UriInfo uriInfo)
{
    if (usernameExists(username))
        throw new ConflictException(uriInfo.getBaseUriBuilder().path("/users/{username}").build(username));

    List<String> errors = new ArrayList<String>();
    if (invalid(email))
        errors.add(email + " is not a valid email address");
    if (empty(name))
        errors.add(name + " must be provided");
    if (!errors.isEmpty())
        throw new BadRequestException(errors);

    //create or update the user
    return user;
}

Here’s the BadRequestException that I use:

import java.util.*;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
import javax.ws.rs.core.Response.*;

/** Thrown to return a 400 Bad Request response with a list of error messages in the body. */
public class BadRequestException extends WebApplicationException
{
    private static final long serialVersionUID = 1L;
    private List<String> errors;

    public BadRequestException(String... errors)
    {
        this(Arrays.asList(errors));
    }

    public BadRequestException(List<String> errors)
    {
        super(Response.status(Status.BAD_REQUEST).type(MediaType.APPLICATION_XHTML_XML)
                .entity(new GenericEntity<List<String>>(errors)
                {}).build());
        this.errors = errors;
    }

    public List<String> getErrors()
    {
        return errors;
    }
}

Notice that the response entity is a GenericEntity<List<String>> and the response format is XHTML. This lets you create your own MessageBodyWriter for a List that gets formatted in nice XHTML.  You can use a class like this to generate a nicely formatted error response body:

@Provider
@Produces(MediaType.APPLICATION_XHTML_XML)
public class ListStringXhtmlWriter implements MessageBodyWriter<List<String>>

Consider the rest of this class an exercise for the reader (or maybe a future post). :)

Written by Zach Cox

June 22, 2009 at 10:33 am

Posted in Java

Tagged with ,

Override the HTTP Request Method in Jersey

with 2 comments

RESTful web services take advantage of all of the HTTP methods including GET, POST, PUT, DELETE, HEAD and OPTIONS.  However, a lot of HTTP libraries (BlackBerry JDE, iPhone SDK, etc) and all browsers only support GET and POST.  There are several ways to get around these deficiencies – in this post I’ll describe two of them and show a Jersey filter for implementing them.

Jersey provides a PostReplaceFilter that looks for the X-HTTP-Method-Override header and changes the request’s method to that header’s value. To use this approach to perform a PUT from your client, just do a POST request and include a “X-HTTP-Method-Override: PUT” header.  The filter will then translate it into a PUT request before handling it.

Ruby on Rails looks for a _method form parameter and changes the request’s method to that parameter’s value.  To use this approach to perform a PUT from your client, just do a POST request and include a “_method=PUT” form parameter.  The Rails version is particularly useful if you’re making the request from an HTML form (updating or deleting a resource, for example).

I combined the two HTTP method overwriting approaches into a new Jersey filter:

import com.sun.jersey.spi.container.*;

/** Clients may override the HTTP method by setting either the X-HTTP-Method-Override header or
 * the _method form or query parameter in a POST request.  If both the X-HTTP-Method-Override
 * header and _method parameter are present in the request then the X-HTTP-Method-Override header
 * will be used.
 *
 * Inspired by https://jersey.dev.java.net/nonav/apidocs/1.1.0-ea/jersey/com/sun/jersey/api/container/filter/PostReplaceFilter.html
 */
public class OverrideHttpMethodFilter implements ContainerRequestFilter
{
    private static final String HEADER = "X-HTTP-Method-Override";
    /** The name of the form or query parameter that overrides the HTTP method. */
    public static final String METHOD = "_method";

    @Override
    public ContainerRequest filter(ContainerRequest request)
    {
        if (request.getMethod().equalsIgnoreCase("POST"))
            if (!override(request.getRequestHeaders().getFirst(HEADER), request))
                if (!override(request.getFormParameters().getFirst(METHOD), request))
                    override(request.getQueryParameters().getFirst(METHOD), request);

        return request;
    }

    private boolean override(String method, ContainerRequest request)
    {
        if (!Strings.isEmpty(method))
        {
            request.setMethod(method);
            return true;
        }

        return false;
    }
}

If you’re creating a web service that uses more than just GET and POST, combining these two approaches will make the unfortunate developers who have to use these flawed HTTP libraries very happy!

Written by Zach Cox

June 17, 2009 at 1:10 pm

Posted in Java

Tagged with , ,

The Top-Level Resource in Jersey

leave a comment »

In RESTful Web Services, the authors define three types of resources exposed by a web service:

  1. Predefined one-off resources for especially important aspects of the application
  2. A resource for every object exposed through the service
  3. Resources representing the results of algorithms applied to the data set

#2 is probably what you think of first when you hear “RESTful web service”.  It’s basic CRUDRuby on Rails was designed to make it super easy to expose these types of resources.  If you have a restaurants table in your databse it gets exposed at http://yourservice.com/restaurants.  Create a new restuarant using POST /restaurants.  View restaurant info at GET /restaurants/{restaurantId}.  Modify a restaurant using PUT /restaurants/{restaurantId}.  Flush a restaurant down the toilet using DELETE /restaurants/{restaurantId}.

#3 is a bit less common but still familiar.  http://google.com/search?q=restful+web+services is Google’s resource for documents about “restful web services”.  It’s the result of using Google’s search algorithms to find relevant documents.

#1 can be used for several different purposes, one of which is to provide a top-level entry point into your web service.  What you choose to put in the representation of the resource at  http://yourservice.com depends on your service.  It could simply provide a way to get to another resource, like http://google.com does (it gives you a search form).  Or it could give you some relevant account info, like https://s3.amazonaws.com (it lists your S3 buckets).  If you’re using XHTML as your representation format, it could provide some documentation about how to use your web service and provide various entry points (ie links) into it.

Using Jersey, it’s incredibly simple to create the top-level resource:

@Path("/")
public class TopLevelResource
{
    @GET
    @Produces(MediaType.APPLICATION_XHTML_XML)
    public String get()
    {
        return "<html><body>This is your top-level resource</body></html>";
    }
}

That’s all there is to it!  The @Path(“/”) annotation makes this resource the top-level resource.  Of course you can add handlers for methods other than GET, but GET should always be used to provide some information about the entire web service.

Written by Zach Cox

June 15, 2009 at 10:55 am

Posted in Java

Tagged with ,

Follow

Get every new post delivered to your Inbox.