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?
Advertisement
Answer
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)); } }