- Assemble framework libraries using Maven.
- Create a POJO interface and an implementation.
- Write a JAX-RS resoure to use Guice constructor injection and JAX-RS annotations.
- Write the Guice bootstrap code.
- Write the embedded Jetty start up code.
- Run and test.
7.4.1.v20110513 1.7 3.0 org.eclipse.jetty jetty-servlet ${jetty.version} com.google.inject guice ${guice.verion} com.sun.jersey jersey-server ${jersey.version} com.sun.jersey.contribs jersey-guice ${jersey.version} junit junit ${junit.version} test maven2-repository.java.net Java.net Repository for Maven http://download.java.net/maven/2/ default
We start with a simple POJO interface:
public interface GuicyInterface { String get(); }And a simple implementation:
public class GuicyInterfaceImpl implements GuicyInterface { public String get() { return GuicyInterfaceImpl.class.getName(); } }Now, write a JAX-RS resource to use both Guice and JAX-RS annotated injections:
import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import com.google.inject.Inject;@Path("/helloguice") public class HelloGuice { private final GuicyInterface gi; @Inject public HelloGuice(final GuicyInterface gi) { this.gi = gi; } @GET @Produces("text/plain") public String get(@QueryParam("x") String x) { return "Howdy Guice. " + "Injected impl " + gi.toString() + ". Injected query parameter "+ (x != null ? "x = " + x : "x is not injected"); } }
Next, compose POJO bindins in a JerseyServletModule. This module will setup the Jersey-based JAX-RS framework for use with Guide injection. The GuiceServletContextListener is used to bootstrap Guice when the servet context is initialized.
import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.servlet.GuiceServletContextListener; import com.sun.jersey.guice.JerseyServletModule; import com.sun.jersey.guice.spi.container.servlet.GuiceContainer; public class HelloGuiceServletConfig extends GuiceServletContextListener { @Override protected Injector getInjector() { return Guice.createInjector(new JerseyServletModule() { @Override protected void configureServlets() { // Must configure at least one JAX-RS resource or the // server will fail to start. bind(HelloGuice.class); bind(GuicyInterface.class).to(GuicyInterfaceImpl.class); // Route all requests through GuiceContainer serve("/*").with(GuiceContainer.class); } }); } }
Finally, write the main method using embedded Jersey to start Guice and Jersey together.
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.DefaultServlet; import org.eclipse.jetty.servlet.ServletContextHandler; import com.google.inject.servlet.GuiceFilter; public class GuiceLauncher { public static void main(String[] args) throws Exception { // Create the server. Server server = new Server(8080); // Create a servlet context and add the jersey servlet. ServletContextHandler sch = new ServletContextHandler(server, "/"); // Add our Guice listener that includes our bindings sch.addEventListener(new HelloGuiceServletConfig()); // Then add GuiceFilter and configure the server to // reroute all requests through this filter. sch.addFilter(GuiceFilter.class, "/*", null); // Must add DefaultServlet for embedded Jetty. // Failing to do this will cause 404 errors. // This is not needed if web.xml is used instead. sch.addServlet(DefaultServlet.class, "/"); // Start the server server.start(); server.join(); } }
If you run the main program on your local host, you can test the servlet using this URL:
http://localhost:8080/helloguice?x=q
Then, you should see a response like this:
Howdy Guice. Injected impl GuicyInterfaceImpl@3aaa3518. Injected query parameter x = qCongratulations! You have now mastered the three most popular IoC frameworks for programming RESTful servlets!
Isn't there any web.xml work that goes along with this?
ReplyDeleteNo. This is pure Jetty embedding which eschrews web.xml entirely. If you prefer a standard servlet container with web.xml, then swap GuiceLauncher with the exact web.xml fragment as shown here:
ReplyDeletehttp://code.google.com/p/google-guice/wiki/Servlets
We found ourselves writing this kind of code over and over, so we extracted it into a small library.
ReplyDeletehttp://github.com/talis/jersey-common
Any idea how to use the Jersey UriConnegFilter with this stack? My goal is doing context negotiation based on url extension without needing to build something, hence me trying to use this servlet. All the documentation I've found only explains how to use it when you're using a jersey servlet. I tried to chain this guy to the juice filter, but it's not even actually a filter, despite it's name - doesn't extend javax.servlet.Filter.
ReplyDeleteSee http://jersey.java.net/nonav/apidocs/1.11/contribs/jersey-guice/com/sun/jersey/guice/spi/container/servlet/package-summary.html for an overview of what goes into web.xml
ReplyDeleteSo useful, thank you very much!
ReplyDeleteThanks for this guide!
ReplyDeleteI was using restlet before and this solution is much more simple an clean than any restlet guice integration I could find.
This post is from 2011, is it still valid?
ReplyDeleteWorked for me Tim.
DeleteThis has been a great help for me. I have a question: how would you change this setup to serve static resources from some location, or is it already set to do that, and if so, which location?
ReplyDeleteThanks again
Hey have you tried this to deploy on a JBoss 7. Getting a "Root-Resource not found"-Exception here.
ReplyDeleteOne thing I don't understand here, and it's kind of deal breaker for me:
ReplyDelete// Route all requests through GuiceContainer
serve("/*").with(GuiceContainer.class);
Why?
I mean Jersey can serve Resources out-of-the-box just fine, why do I have to route everything through guice? I actually only want guice to set @Inject dependencies, but not the Resources itself.
This comment has been removed by the author.
DeleteGuice has to inject the Resource so that any injected resources that are required by each @Path (resource you have configured for the endpoint) has Guice IoC injection when created. This is typical "Guice" the originating class has to be injected, in order to inject children.
DeleteI suppose there is nothing stopping you from creating an Injection and manually injecting a "root" level object when you need something handled by Guice IoC (not very elegant though).