Search code examples
javajax-rscdijersey-2.0

Dependency Injection in jersey 2.17


I have a resource class

@Path("/rest")
public class DemoResourceController {
    @Inject
    DemoService demoService;

    @Path("/get/demo")
    @GET
    @Produces(APPLICATION_JSON)
    public Response getDemoLists() {
        List<String> demoList=demoService.getDemoList();
        return  Response.ok(demoList).build();
    }

I tried the answers in the post Dependency injection with Jersey 2.0

if i use

compile group: "org.glassfish.jersey.ext.cdi" , name: "jersey-cdi1x" , version: "2.17"
compile group: "org.glassfish.jersey.ext.cdi" ,name: "jersey-weld2-se" , version: "2.17"

On launching the server i get

org.jboss.weld.exceptions.IllegalArgumentException: WELD-001408: 
Unsatisfied dependencies for type demoService with qualifiers @Default
[BackedAnnotatedField] @Inject  DemoResourceController.demoService at injection point

If i remove the above dependencies then i get

javax.servlet.ServletException: A MultiException has 3 exceptions.  They are:
1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no
   object available for injection at SystemInjecteeImpl(requiredType=DemoService,parent=DemoResourceController,qualifiers={},position=- 1,optional=false,self=false,unqualified=null,1952079126)**
2. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of DemoResourceController errors were found
3. java.lang.IllegalStateException: Unable to perform operation: resolve on package.DemoResourceController

org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:421)

The resourceconfig class is

public class ApplicationConfig extends ResourceConfig {

  public ApplicationConfig() {
    register(new ApplicationBinder());
    packages(..name of packages..);
  }

The binder class is

public class ApplicationBinder extends AbstractBinder{
  @Override
  protected void configure() {
      bind(DemoService.class).to(DemoServiceImpl.class);
  }
 }

I use tomcat in embedded mode and add init parameters

Context ctx = tomcat.addContext("/", new File("web-app").getAbsolutePath());
Wrapper wrapper = ctx.createWrapper();
wrapper.addInitParameter("javax.ws.rs.Application","xx.xx.ApplicationConfig");

How do i inject the service in the controller? Is injection the preferred way to unit test it (when the service implementation,say demoServiceImpl is calling another service say,XService) and unit tests should not depend on Xservice and hence demoServiceImpl How would i inject a mock of the service into the controller from the test?


Solution

  • In your second attempt (without the cdi dependencies; using HK2) your binding is incorrect. It should be

    bind(Implementation).to(Contract)
    // - i.e.
    bind(DemoServiceImpl.class).to(DemoService.class);
    

    You have it the other way around.

    As far as testing, if you have the test in same package (in the test area of the project) you should be able to assign the service, as it's package private. Though personally, I've gotten into the habit of constructor injection. Another thing you can do is use Jersey Test Framework. You can see an complete example here, where a mock service is injected