Question

I've been using Jersey 1.X with Google Guice for dependency injection. Switching to Jersey 2.X seems to mean you need to use HK2 for dependency injection instead, I'm struggling to find a few things that I had in Guice.

In Jersey 1.X with Guice, I would have something like this for the application:

public class GuiceServletTestConfig extends GuiceServletContextListener  {
    @Override
    protected Injector getInjector() {
        return Guice.createInjector(new ServletModule(){
            @Override
            protected  void configureServlets(){
                bind(MyResource.class);
                serve("/*").with(GuiceContainer.class);
                bind(MyDAO.class).to(MyDAOSQL.class)
            }
        });
    }
}

And something like this for tests:

public class GuiceServletTestConfig extends GuiceServletContextListener  {
    @Override
    protected Injector getInjector() {
        return Guice.createInjector(new ServletModule(){
            @Override
            protected  void configureServlets(){
                bind(MyResource.class);
                serve("/*").with(GuiceContainer.class);
            }

            @Provides
            MyDAO provideMockMyDAO(){
                MyDAO dao = mock(MyDAO.class);
                return dao;
            }
        });
    }
}

Any my resrouce would look like this:

@Path("myresource")
public class MyResource {
    private MyDAO myDAO;

    @Inject
    protected void setMyDAO(MyDAO myDAO) {
        this.myDAO = myDAO;
    }

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Response get() {
        // Do something with myDAO
        // Return response    
    }
}

That was I can define mocks for my tests and everything is good.

With Jersey 2.X however, I cannot find any equivalent for the @Provides annotation. MyResource is effectively the same. For dependency injection for the real application, I have:

public class Application extends ResourceConfig {
    public Application() {
        packages("com.my.package.resources");

        register(new AbstractBinder() {
            @Override
            protected void configure() {
                bind(MyDAOSQL.class).to(MyDAO.class);
            }
        });
    }
}

But I don't know how to provide mocks for tests. Anyone knoe how?

Was it helpful?

Solution 2

OK, so I figured out a way that works for me. One thing that threw me off was the swapping of the bind().to() from Guice to HK2. In Guice, you write:

bind(Abstract.class).to(Concrete.class)

Where as in HK2, you write:

bind(Concrete.class).to(Abstract.class)

The way to get the provides behaviour can be achieved with the following code:

public class MyResourceIT extends JerseyTest {
    @Override
    protected Application configure() {
        ResourceConfig resourceConfig = new ResourceConfig();
        resourceConfig.register(MyResource.class);

        resourceConfig.register(new AbstractBinder() {
            @Override
            protected void configure() {
                bind(provideMyDaoMock()).to(MyDao.class);
            }

            private MyDao provideMyDaoMock() {
                MyDao myDaoMock = mock(MyDao.class);
                return myDaoMock;
            }
        });
        return resourceConfig;
    }
}

OTHER TIPS

HK2 allows you to bind Factories that work just like @Provides. Here is the javadoc. I do think it isn't as convenient since you have to create a class that implements Factory. I may add an enhancement Jira to do a CDI style @Produces.

Also, you can continue to use Guice in Jersey (many people do) by using the Guice-HK2 bridge. There are some limitations when using the Bridge (like having to use @HK2Inject for classes created by Guice but to be injected with HK2 services), but most things do still work.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top