I'm using dropwizard 1.0.5, dropwizard-guicey 4.0.1 (https://github.com/xvik/dropwizard-guicey), spinscale quartz implementation 3.0.0 (https://github.com/spinscale/dropwizard-jobs).
I want to be able to inject my dependencies into the job instances that quartz/spinscale creates. To do this, I tried to load in the following library https://github.com/spinscale/dropwizard-jobs/tree/master/dropwizard-jobs-guice
The problem with this is, when the Guice dropwizard jobs bundle is created, the Guice injector is not yet initialized, so I get an NPE.
Example:
MyApplication.java
@Override
public void initialize(Bootstrap<MyConfiguration> bootstrap) {
// Initialize Guice for dependency injection
GuiceBundle guiceBundle = GuiceBundle.builder()
.bindConfigurationInterfaces()
.enableAutoConfig(getClass().getPackage().getName())
.modules(new MyModule(bootstrap.getMetricRegistry()))
.build();
bootstrap.addBundle(guiceBundle);
bootstrap.addBundle(new GuiceJobsBundle(guiceBundle.getInjector()));
Exception:
Exception in thread "main" java.lang.NullPointerException: Guice not initialized
at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:226)
To fix this, I tried creating my own version of the GuiceJobsBundle
that takes in the GuiceBundle
and doesn't set the injector until bundle.run()
is called. But still, I get an NPE.
MyApplication
@Override
public void initialize(Bootstrap<MyConfiguration> bootstrap) {
// Substitute environment variable references in the configuration file
bootstrap.setConfigurationSourceProvider(new SubstitutingSourceProvider(
bootstrap.getConfigurationSourceProvider(),
new EnvironmentVariableSubstitutor(false, true)
));
// Initialize Guice for dependency injection
GuiceBundle guiceBundle = GuiceBundle.builder()
.bindConfigurationInterfaces()
.enableAutoConfig(getClass().getPackage().getName())
.modules(new MyModule(bootstrap.getMetricRegistry()))
.build();
bootstrap.addBundle(guiceBundle);
bootstrap.addBundle(new GuiceyJobsBundle(guiceBundle));
}
GuiceyJobsBundle
public class GuiceyJobsBundle extends JobsBundle {
private GuiceBundle guiceBundle;
public GuiceyJobsBundle(GuiceBundle guiceBundle) {
this.guiceBundle = guiceBundle;
}
@Override
public void run(Environment environment) {
JobManager jobManager = new GuiceJobManager(guiceBundle.getInjector());
environment.lifecycle().manage(jobManager);
}
}
When is a bundle's run()
method called? And has anybody found a working solution for this?
You were almost right about the last fix, you just forget to bind configuration jobManager.configure(configuration)
(that's why NPE was thrown).
But you can do integration without bundles at all. I see you already use classpath scan, so just drop these extensions somewhere:
@Singleton
public class JobsManager extends GuiceJobManager {
@Inject
public JobsManager(Injector injector, JobsAppConfiguration configuration) {
super(injector);
configure(configuration);
}
}
This will be recognized as Manged bean and will start/stop quartz context. Internally it searches for jobs in registered guice bindngs (using dropwizard-jobs logic).
public class JobsInstaller implements FeatureInstaller<Job>, TypeInstaller<Job> {
private final Reporter reporter = new Reporter(JobsInstaller.class, "jobs =");
@Override
public boolean matches(Class<?> type) {
return FeatureUtils.is(type, Job.class);
}
@Override
public void install(Environment environment, Class<Job> type) {
// here we can also look for class annotations and show more info in console
// (omitted for simplicity)
reporter.line("(%s)", type.getName());
}
@Override
public void report() {
reporter.report();
}
}
This installer simply binds all jobs to guice context so JobsManager
could install them (just to avoid manual jobs binding).
I add compete example to guicey-examples repo: https://github.com/xvik/dropwizard-guicey-examples/tree/master/dropwizard-jobs