简体   繁体   中英

JerseyTest unsatisfied dependency (Dependency Injection)

I need to test my RESTful service and I thought the most appropriate way to do it would be using the Jersey Test Framework since I am already using Jersey for my service.

However, when running a simple test I am getting a UnsatisfiedDependencyException because the implementation of the DAO I am using in the service is not found (it's being set via DI). This error used to happen to me everytime I modified my pom.xml Maven configuration file, mostly when adding or removing dependencies. Supposedly, the IDE I'm using, IntelliJ IDEA is supposed to regenerate the artifacts automatically, but for me to avoid this dependency failure I needed to remove the old artifact from the Tomcat server deployment options as well as from the project structure, and add it again.

The problem here is that the test framework is using a separate server, as the documentation said. I am using the following one:

<dependency>
    <groupId>org.glassfish.jersey.test-framework.providers</groupId>
    <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
    <version>2.23.1</version>
</dependency>

I don't know how to solve the dependency issue if I am using a different server.

The top error message in the exception stack says:

org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl

Any ideas?

Edit. I managed to patch it with a dirty solution.

First, let me show you how I was injecting the DAO:

// Binder.java
public class Binder extends AbstractBinder {
    @Override
    protected void configure() {
        bind(TournamentDao.class).to(ITournamentDao.class).in(Singleton.class);
    }
}

// DependencyInjectionFeature.java
@Provider
public class DependencyInjectionFeature implements Feature {
    @Override
    public boolean configure(FeatureContext context) {
        context.register(new Binder());
        return true;
    }
}

// EventSchedulerService.java
@Path("eventscheduler")
public class EventSchedulerService {
    private ITournamentDao dao;

    @Inject
    public EventSchedulerService(ITournamentDao tournamentDao) {
        dao = tournamentDao;
    }
}

The web configuration file web.xml scans the package where these classes are placed (the package has the same name than the one where the test exists) and perform the dependency injection since it finds the @Provider annotation.

To patch my issue I did the exact same thing in the test class:

public class EventSchedulerServiceTest extends JerseyTest {
    protected Application configure() {
        ResourceConfig config = new ResourceConfig(EventSchedulerService.class);
        config.register(new AbstractBinder() {
            @Override
            protected void configure() {
                bind(TournamentDao.class).to(ITournamentDao.class).in(Singleton.class);
            }
        });
        return config;
    }
}

Obviously this is a bad idea because now I have duplicate code; but it did the trick. I'd like to know how to make the test server to use the service configuration correctly.

I remember from a previous discussion in the comments here , you had the problem of not using a ResourceConfig to configure your main application. You we instead using web.xml.

The reason you are using a Feature annotated with @Provider is that you we're using package scanning in your web.xml

<init-param>
    <param-name>jersey.config.server.provider.packages</param-name>
    <param-value>your.packages.to.scan</param-value>
</init-param>

The package scan picked up the @Provider on the Feature , and automatically registers it. This provider is what is used to register the Binder , which is what configured the dependency injection.

As mentioned, a Jersey application can be configured in a ResourceConfig or in a web.xml. Anything jersey configuration you can do in the web.xml, you can also do in the ResourceConfig . There are a bunch of different ways you can register components with the ResourceConfig

  • You can just call register

     config.register(new DependencyInjectionFeature()); 
  • You can also package scan, the same way you are doing in the web.xml, by calling packages

     config.packages("your.packages.to.scan"); 
  • You should also look at your implementation of the Binder class. It extends AbstractBinder . The look at how you are currently configuring the DI in the test

     config.register(new AbstractBinder() { @Override protected void configure() { ... } }); 

    You are registering an AbstractBinder instance. So you know that calling you can register the DI configuration calling register on the ResourceConfig , so you could instead of registering a different binder, just register an instance of the Binder class

     config.register(new Binder()); 

So you have some options.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM