Java – using Jersey’s dependency injection
If I use Jersey 1.12, and I have multiple resource classes, and they all need to access some shared context, what is the best way to inject dependencies, whether in the constructor of the resource class or in the handler method? Do I need to use an external Di library, or what is built into Jersey?
Maybe foos's resources look like this:
package com.example.resource; import javax.ws.rs.GET; import javax.ws.rs.Produces; import javax.ws.rs.Path; @Path("/some/api/path/foo") public class FooResource { @GET @Produces("text/html") public String getFoo(@QueryParam("id") String id) { Foo foo = /* get a Foo from some shared context based on id */ /* Process foo into a String */ } }
And bars:
package com.example.resource; import javax.ws.rs.GET; import javax.ws.rs.Produces; import javax.ws.rs.Path; @Path("/some/api/path/bar") public class BarResource { @GET @Produces("text/html") public String getBar(@QueryParam("id") String id) { Bar bar = /* get a Bar from some shared context based on id */ /* Process bar into a String */ } }
Solution
I finally used Google Guice, a lightweight Di framework that integrates well with Jersey That's what I have to do:
First, I'm in POM Dependency added to XML:
<dependency> <groupId>com.google.inject</groupId> <artifactId>guice</artifactId> <version>3.0</version> <scope>compile</scope> </dependency> <dependency> <groupId>com.sun.jersey.contribs</groupId> <artifactId>jersey-guice</artifactId> <version>1.12</version> <scope>compile</scope> </dependency>
I want to implement Dao as a singleton with interface:
public interface MySingletonDao { // ... methods go here ... }
And specific implementation:
@Singleton public class ConcreteMySingletonDao implements MySingletonDao { // ... methods go here ... }
Decorate the resource class like this:
@Path("/some/path") @RequestScoped public class MyResource { private final MySingletonDao mySingletonDao; @Inject public MyResource(MySingletonDao mySingletonDao) { this.mySingletonDao = mySingletonDao; } @POST @Produces("application/json") public String post() throws Exception { // ... implementation goes here ... } }
Created a class that will perform binding:
public class GuiceConfig extends Guiceservletcontextlistener { @Override protected Injector getInjector() { return Guice.createInjector(new JerseyServletModule() { @Override protected void configureServlets() { bind(MyResource.class); bind(AnotherResource.class); bind(MySingletonDao.class).to(ConcreteMySingletonDao.class); serve("/*").with(GuiceContainer.class); } }); } }
I use jetty instead of GlassFish to actually act as a server In my functional test, it looks like:
private void startServer() throws Exception { this.server = new Server(8080); ServletContextHandler root = new ServletContextHandler(server,"/",ServletContextHandler.SESSIONS); root.addEventListener(new GuiceConfig()); root.addFilter(GuiceFilter.class,"/*",EnumSet.of(DispatcherType.REQUEST)); root.addServlet(EmptyServlet.class,"/*"); this.server.start(); }
Emptyservlet is the sample code from sunny Gleason, which is given as the answer: https://stackoverflow.com/a/3296467 – my original
root.addServlet(new ServletHolder(new ServletContainer(new PackagesResourceConfig("com.example.resource"))),"/*");
Not a line
root.addServlet(EmptyServlet.class,"/*");
However, this causes Jersey to try to perform dependency injection instead of Guice, which will lead to runtime errors