Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dependency Injection with Jersey

If I am using Jersey 1.12, and I have multiple resource classes, and they all need to access some shared context, what's the best way to inject a dependency, whether it be in the constructor for the resource class, or into the handler method? Do I need to use an external DI library, or does Jersey have something built-in?

i.e. maybe the resource for Foos looks 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 for 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 */
    }
}
like image 887
Shaggy Frog Avatar asked May 23 '12 23:05

Shaggy Frog


People also ask

What are the three types of dependency injection?

There are three types of dependency injection — constructor injection, method injection, and property injection.

What is HK2 Jersey?

Jersey is a Java Framework that is commonly used to help generate REST Api. HK2 is a lightweight framework which allow Inversion of Control (IoC) and dependency injection (DI)

What is Jersey API?

Jersey RESTful Web Services framework is open source, production quality, framework for developing RESTful Web Services in Java that provides support for JAX-RS APIs and serves as a JAX-RS (JSR 311 & JSR 339) Reference Implementation. Jersey framework is more than the JAX-RS Reference Implementation.

What is HK2 dependency injection?

HK2 (Hundred-Kilobyte Kernel) is a light-weight and dynamic dependency injection framework and is a part of the GlassFish Application Server. HK2. Developer(s) Oracle Corporation. Stable release.


2 Answers

I ended up using Google Guice, which is a lightweight DI framework that integrates well with Jersey. Here's what I had to do:

First, I added dependencies in the pom.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 wanted a DAO implemented as a singleton with an interface:

public interface MySingletonDao
{
    // ... methods go here ...
}

and a concrete implementation:

@Singleton
public class ConcreteMySingletonDao implements MySingletonDao
{
    // ... methods go here ...
}

Decorated the resource classes like so:

@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 do the bindings:

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 used Jetty instead of Glassfish to actually act as the server. In my functional test, that looks something 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();
}

The EmptyServlet comes from Sunny Gleason's sample code given out as an answer at: https://stackoverflow.com/a/3296467 -- I originally had

root.addServlet(new ServletHolder(new ServletContainer(new PackagesResourceConfig("com.example.resource"))), "/*");

instead of the line

root.addServlet(EmptyServlet.class, "/*");

But that caused Jersey to try and perform the dependency injection instead of Guice, which caused runtime errors.

like image 133
Shaggy Frog Avatar answered Sep 24 '22 02:09

Shaggy Frog


you can use SingletonTypeInjectableProvider: http://jersey.java.net/nonav/apidocs/1.12/jersey/com/sun/jersey/spi/inject/SingletonTypeInjectableProvider.html

sample:

ResourceConfig resourceConfig = new DefaultResourceConfig();
resourceConfig.getSingletons().add(
        new SingletonTypeInjectableProvider<Context, SingletonType>(
               SingletonType.class, new SingletonType()) {});{code}

or you can create SingletonTypeInjectableProvider descendant, annotate it with @Provider add it as a class. The you can inject provided instance wherever you need and where standard Jersey injection kicks in.

like image 22
Pavel Bucek Avatar answered Sep 25 '22 02:09

Pavel Bucek