Injecting singleton in guice module - java

I have written some modules with guice. These are working great.
I have also some singletons or a logger I need in my modules which I want to inject into these modules.
For example I have my JpaModule where I need my Configuration.
ConfigurationModule:
#Singleton
public class ConfigurationModule extends AbstractModule {
#Override
protected void configure() {
bind(Configuration.class).toProvider(ConfigurationProvider.class).in(Singleton.class);
}
}
JpaModule:
public class JpaDaoModule extends AbstractModule {
#Inject
Configuration config;
#Override
protected void configure() {
// ... Read config and do something
}
}
Call to Guice:
Guice.createInjector(new ConfigurationModule(), new JpaDaoModule());
How can I accomplish this? Or how can I provide the configuration to the JpaModule the guicy way?
/Kind regards
Christian

This is not possible. In the configure() method you set up your bindings. You cannot expect them to be available already. Also, modules are not eligible for injection per se. You can, however, get access to Guice-managed instances in providers or #Provides methods.
#Provides
#Named("myConfigItem")
String provideSomeConfigItem(Configuration config) {
return config.get("myConfigItem");
}

Related

How inject Hk2 beans with Guice

There is a dropwizard app, which is jersey based.
I rewrote Hk2 bean definitions into Guice and now I can inject Guice beans into Jersey Resources,
but I noticed that Hk2 beans, defined in dropwizard bundles, which I cannot rewrite, are not
visible by Guice and it fails to inject dependencies defined in Hk2.
Guice doesn't see beans defined in Hk2 bundles and Guice creates new uninitialized beans by default.
I disabled this behavior with requireExplicitBindings.
I experimented with HK2IntoGuiceBridge, but its matcher is not invoked for beans I am interested in.
ConfiguredBundleX is located in external artifact.
I tried to copy and translate bean definitions from bundles and stuck with jersey bean Provider<ContainerRequest>, I have no idea where it comes from.
public class ConfiguredBundleX implements ConfiguredBundle<MyAppConf> {
public void run(T configuration, Environment environment) throws Exception {
environment.jersey().register(new AbstractBinder() {
protected void configure() {
this.bind(new MyHk2Bean()).to(MyHk2Bean.class);
}
});
}
}
public class DependsOnHk2Bean { #Inject public DependsOnHk2Bean(MyHk2Bean b) {} }
public class MainModule extends AbstractModule {
private final ServiceLocator locator;
protected void configure() {
binder().requireExplicitBindings();
install(new HK2IntoGuiceBridge(locator));
bind(DependsOnHk2Bean.class);
}
public class GuiceFeature implements Feature {
public boolean configure(FeatureContext context) {
ServiceLocator locator = ServiceLocatorProvider.getServiceLocator(context);
GuiceBridge.getGuiceBridge().initializeGuiceBridge(locator);
Injector injector = Guice.createInjector(
new HK2IntoGuiceBridge(locator),
new MainModule(locator));
GuiceIntoHK2Bridge guiceBridge = locator.getService(GuiceIntoHK2Bridge.class);
guiceBridge.bridgeGuiceInjector(injector);
return true;
}
}
// ...
public void initialize(Bootstrap<X> bootstrap) {
bootstrap.addBundle(new ConfiguredBundleX());
}
public void run(X config, Environment env) {
env.jersey().register(new GuiceFeature());
}
Unfortunately in Guice beans you have to use #HK2Inject rather than #Inject in order to inject hk2 beans into Guice. So in your code above you would do:
public class DependsOnHk2Bean { #HK2Inject public DependsOnHk2Bean(MyHk2Bean b) {} }
This is because of limitation in guice (it may be fixed by now) such that #Inject behavior could not overwritten
I have not tried the above code myself so I'm not sure it'll work, but that was the deal back when the bridge was written...
See HK2Inject and injecting-hk2-services-into-guice-services
After digging Guice and HK2ToGuiceTypeListenerImpl I figured out that there is bindListener to kind of intercept missing bindings and pull them from somewhere. #HKInject code is there, but I noticed that the listener is not called for some bean including the bean I was interested in. Yes HKInject doesn't support constructor injection (4.2.1 version)
So I decided to manually import HK beans and bind them in Guice.
Dropwizard terminology is horrible there are methods get context something, get admin context is totally something different and beans must be get with getService method!
#RequiredArgsConstructor
public class HkModule extends AbstractModule {
private final ServiceLocator locator;
#Override
protected void configure() {
binder().requireExplicitBindings();
Provider<Bar> barProvider = locator.getService(
new TypeLiteral<Provider<Bar>>(){}.getType());
bind(Bar.class).toProvider(barProvider);
bind(Foo.class).toInstance(locator.getService(Foo.class));
}
}

Creating guice injector of another module installed inside current module

Have an interface that needs many implementations to be bound to it.
Going for the following design because of many constraints (May not seem good, please ignore the design).
Is it possible to create an injector for another module installed in current module while still running the configure() method for the current module.?
public class CurrentModule extends AbstractModule{
#Override
protected void configure() {
install(new OtherModule());
final someInterface getInstance = methodToGetInstance();
bind(SomeInterface.class).to(getInstance);
}
public SomeInterface methodToGetInstance() {
Injector injector = Guice.createInjector(new OtherModule());
return new ClassImplementingSomeInterface(injector.getInstance(dependency));
}
}
Yes, what you ask is possible with provider methods. This is how you should do it:
class CurrentModule extends AbstractModule {
#Override protected void configure() {
install(new OtherModule());
// Optional, but it's good to write it if the dependency becomes missing from OtherModule.
requireBinding(DependencyFromOtherModule.class);
}
#Singleton
#Provides SomeInterface createSomeInterface(DependencyFromOtherModule dependency) {
return new ClassImplementingSomeInterface(dependency);
}
}

Inject Configuration in Guice AbstractModule in Dropwizard Application

I am working on an application developed using Guice and Dropwizard, where we are creating different bundles like guice bundle, migrations bundle, etc. and adding them to bootstrap in initialize() method.
I am trying to inject Configuration object in MyModule class, but unable to do so.
Following is the code for Application class:
public class MyApplication extends Application<MyConfiguration> {
public static void main(String args[]) throws Exception {
new MyApplication().run(args);
}
private GuiceBundle<MyConfiguration> guiceBundle = GuiceBundle.<MyConfiguration> newBuilder()
.addModule(new MyModule()).enableAutoConfig(getClass().getPackage().getName())
.setConfigClass(MyConfiguration.class).build(Stage.DEVELOPMENT);
#Override
public void initialize(Bootstrap<MyConfiguration> bootstrap) {
bootstrap.addBundle(guiceBundle);
}
#Override
public void run(MyConfiguration configuration, Environment environment) throws Exception {
...
}
}
Below is Module class which extends AbstractModule:
public class MyModule extends AbstractModule {
#Override
protected void configure() {
}
}
With this approach, I am finding it hard to inject Configuration object in Module class, as Configuration object is not available in initialize() method, but is available in run() method.
Is there any alternative way to do this?
Note: I am aware of another way where you can create an object of Module class in run() method for creating an injector (with configuration and environment object passed as parameters in the constructor of MyModule class). But this would require me to register all Managed objects and all resources in run() method. I want to avoid doing that.
Guice modules are classes that store the configuration, and are resolved when an injector is created. You cannot explicitly inject an object in your module.
I don't think I would be able to tell you much more without looking into internal of GuiceBundle.

Using custom factory HK2 DI with Jersey

I'm using the HK2 container in my Jersey application . I need to use my custom factory method to get the injected instance from the HK2 container.
For example ,
// Here I declare the IOC binding.
public class ApplicationBinder extends AbstractBinder {
#Override
protected void configure() {
bind(Logger.class).to(ILogger.class).in(Singleton.class);;
bind(MySqlRepository.class).to(IRepository.class).in(Singleton.class);
}
}
public class MyApplication extends ResourceConfig {
public static ApplicationBinder binder ;
public MyApplication () {
binder = new ApplicationBinder();
register(binder);
packages(true, "com.myapplication.server");
}
}
Here is my code :
public class BusinessLogic
{
//#Inject
//ILogger logger ;
//Instead
ILogger logger = DependencyResolver .resolve(ILogger.class) // resolve will get ILogger from HK2 container
}
The reason I need to do this way is for sometimes , I allocate classes manually which has dependencies , so in this way each use of #Inject return null.
For example, if I use new BusinessLogic() , then the logger with #Inject is null. I have to bind businesslogic also and use IOC in order to get the ILogge.
I need something like this:
public class DependencyResolver {
public static <T> T resolve(Class<T> beanClass){
return instance;
}
}
I need to use the DependencyResolver in order to get the instances I registered in MyApplication.
Any suggestions.
Thanks in advance...
I'm not 100% sure what exactly you want to do, but ...
I think you misunderstood AbstractBinder.bind(...) or bindings itself. Also, afaig you can't inject something into an instance which is not kinda managed component (like your BusinessLogic).
See jersey.java.net - ioc for examples regarding your BusinessLogic. You may have a look at ComponentProvider and/or InjectableProvider
For your ILogger I would suggest to create and bind a Factory like this:
public class LoggerFactory implements Factory<ILogger> {
// inject stuff here if you need (just an useless example)
#Inject
public LoggerFactory(final UriInfo uriInfo) {
this.uriInfo = uriInfo;
}
#Override
public ILogger provide() {
// here you resolve you ilogger
return MyLocator.resolve(ILogger.class);
}
#Override
public void dispose(ILogger instance) {
// ignore
}
}
Bind Factory
public class ApplicationBinder extends AbstractBinder {
#Override
protected void configure() {
bindFactory(LoggerFactory.class).to(ILogger.class).in(PerLookup.class /* or other scopeAnnotation if needed */);
// what's you Logger.class ?
// bind(Logger.class).to(ILogger.class).in(Singleton.class);
// bind(MySqlRepository.class).to(IRepository.class).in(Singleton.class);
}
}
Hope this was helpful somehow. Maybe someone is willing to write something about Providers for your case.

How to pass parameters to REST resource using Jersey 2.5

I have a Java server which serves my clients (Not application server).
Now I'm interested to add REST support. I've initialized a Jetty server and created few REST resources.
My question is: How can I pass parameters at the creation of the REST resources?
Normally I would prefer in the constructor of each resource, but I don't control it.
I understand there is a way to inject dependencies. How to do it using Jersey 2.5??
Thank you!
Define your Application
public class MyApplication extends ResourceConfig {
public MyApplication() {
register(new FacadeBinder());
register(JacksonFeature.class);
register(MyEndpoint.class);
}
Configure injection
public class FacadeBinder extends AbstractBinder {
#Override
protected void configure() {
bind(MyManager.class).to(MyManager.class);
}
}
Inject configured classes in your endpoint
#Path("/jersey")
public class MyEndpoint {
#Inject
MyManager myManager;
...
}
I'm not sure to understand what do you mean with dependencies.
You should check this: https://jersey.java.net/documentation/latest/user-guide.html#d0e1810
Another option besides using dependency injection is to instantiate and register the REST endpoint yourself. Jersey allows you to do this in a very similar fashion as dependency injection as shown in Dymtro's example. Borrowing liberally from Dymtro, define your endpoint:
#Path("/jersey")
public class MyEndpoint {
private MyManager myManager;
public MyEndpoint(MyManager myManager) {
this.myManager = myManager;
}
....
}
Define your application:
public class MyApplication extends ResourceConfig {
public MyApplication(MyManager myManager) {
register(JacksonFeature.class);
register(new MyEndpoint(myManager));
....
}
}

Categories

Resources