I want to use Guava's Service Manager to manage services in my Dropwizard application.
ServiceManagerProvider
provides the service manager:
@Singleton
public class ServiceManagerProvider implements Provider<ServiceManager> {
@Inject
Set<Service> services;
public static Multibinder<Service> serviceRegistry(Binder binder) {
return Multibinder.newSetBinder(binder, Service.class);
}
@Override
public ServiceManager get() {
return new ServiceManager(services);
}
}
ManagedGuavaServices
is a Managed
object that interacts with the Service Manager to start/stop services:
public class ManagedGuavaServices implements Managed {
@Inject
private ServiceManager _serviceManager;
@Inject
public ManagedGuavaServices(ServiceManager serviceManager) {
_serviceManager = serviceManager;
}
@Override
public void start() throws Exception {
_serviceManager.startAsync();
}
@Override
public void stop() throws Exception {
_serviceManager.stopAsync();
}
}
MyModule
is the module where the Guice bindings are specified:
public class MyModule extends DropwizardAwareModule<MyConfig> {
...
@Override
protected void configure() {
bind(ServiceManager.class).toProvider(ServiceManagerProvider.class);
bind(Managed.class).to(ManagedGuavaServices.class).in(Singleton.class);
}
}
And MyApplication
is the Dropwizard application that depends on MyModule
:
public class MyApplication extends Application<MyConfig> {
@Inject
private Managed managedServices;
...
@Override
public void initialize(Bootstrap<MyConfig> bootstrap) {
bootstrap.addBundle(GuiceBundle.builder()
.printDiagnosticInfo()
.printGuiceBindings()
.enableAutoConfig(getClass().getPackage().getName())
.modules(
new MyModule()
)
.build());
}
...
@Override
public void run(MyConfig config, Environment environment) {
environment.lifecycle().manage(managedServices);
}
}
It seems like everything has been wired together, but when I run the application, I get the error message:
java.lang.NullPointerException
at java.base/java.util.Objects.requireNonNull(Objects.java:221)
at io.dropwizard.lifecycle.setup.LifecycleEnvironment.manage(LifecycleEnvironment.java:45)
at com.example.MyApplication.run(MyApplication.java:188)
at com.example.MyApplication.run(MyApplication.java:60)
at io.dropwizard.cli.EnvironmentCommand.run(EnvironmentCommand.java:44)
at io.dropwizard.cli.ConfiguredCommand.run(ConfiguredCommand.java:87)
at io.dropwizard.cli.Cli.run(Cli.java:78)
at io.dropwizard.Application.run(Application.java:94)
at com.example.MyApplication.main(MyApplication.java:70)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at com.webobjects._bootstrap.WOBootstrap.main(WOBootstrap.java:118)
which essentially means that the injected managedServices
in MZPaymentApplication
is null when the application is run.
What is wrong here? Is it the same problem as in this SO question? If so, where should the @PostConstruct
be?
The problem is in managedServices
being field in Application and not injectable, since app object is not configured by Guice (usually in Dropwizard it is created via new
keyword).
So you should store your GuiceBundle
instance in initialize
method as field and then access any Guice binding in run
method with guiceBundle.getInjector().getInstance()
, e.g.:
public class MyApplication extends Application<MyConfig> {
private GuiceBundle<MyConfig> guiceBundle;
public static void main(String[] args) throws Exception {
new MyApplication().run(args);
}
@Override
public void initialize(Bootstrap<MyConfig> bootstrap) {
guiceBundle = GuiceBundle.builder()
.printDiagnosticInfo()
.printGuiceBindings()
.enableAutoConfig(getClass().getPackage().getName())
.modules(
new MyModule()
)
.build();
bootstrap.addBundle(guiceBundle);
}
@Override
public void run(MyConfig config, Environment environment) throws Exception {
environment.lifecycle().manage(guiceBundle.getInjector().getInstance(Managed.class));
}
}