1

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.

dabadaba
  • 9,064
  • 21
  • 85
  • 155

1 Answers1

0

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.

Community
  • 1
  • 1
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
  • I understand now. So basically I need to configure the server used in the test the same way than the "main" one. So for each `@Provider` I have I just need to just `register()` it? For example, I have custom exception mappers. But I am having trouble with some exceptions, how should I configure it in order to reach the same behaviour? – dabadaba Jul 04 '16 at 14:22
  • Same thing. You can register the mapper the same way; package scanning or explicit registration with the `register` method – Paul Samsotha Jul 04 '16 at 14:24
  • But I don't have a mapper for 404 errors. I think it's built in as default Jersey behaviour. When you throw a `NotFoundException()` it's automatically generating a 404 response. But in my test it's responding with code 500. – dabadaba Jul 04 '16 at 14:26
  • This is an unrelated topic for this post. Please continue discussion in other post – Paul Samsotha Jul 04 '16 at 14:29