I am new to Guice so this might be a basic question. Guice beans get created correctly with below code in Module
public class MyModule extends AbstractModule {
#Override
protected void configure() {
ClassA classAObj = ClassA.standard().build();
bind(ClassA.class).toInstance(classAObj);
ClassB classBObj = new ClassB(classAObj);
bind(ClassA.class).toInstance(classBObj);
}
}
but I want to create beans for ClassA and ClassB using annotations. I tried below code in Module:
public class MyModule extends AbstractModule {
#Provides #Singleton public ClassA getClassA() {
return ClassA.standard().build();
}
#Provides #Singleton public ClassB getClassB() {
Injector injector = Guice.createInjector(new MyModule());
return new ClassB(injector.getInstance(ClassA.class));
}
}
I also tried few other combinations but they don't seem to be working. Can someone please let me know
How to inject bean of ClassA as constructor parameter while creating bean of ClassB using annotations in Guice?
AND/OR
How to set bean of ClassA as class level variable of ClassB(without constructor route)?
You can simply write the following:
#Provides #Singleton
public ClassB getClassB(ClassA classA) {
return new ClassB(classA);
}
By passing ClassA as parameter of getClassB, Guice will consider that ClassB depends on ClassA, and will know that it must call getClassA() before calling getClassB(ClassA).
Related
I'm working on a project with Vert.x that uses Dagger for DI, and there's a class that's creating an unsustainable problem with how big the injection is done.
This is the class that I have:
public class ClassManager {
private List<ParentClass> all = new ArrayList<>();
#Inject
public ClassManager(ParentClass... classes) {
if (classes != null) {
all.addAll(Arrays.asList(classes));
}
}
//other methods down here
}
The problem being that, as of right now, we have 32 classes that extend from this abstract class ParentClass, so the injection right now is as this:
#Provides
#Singleton
public ClassManager provideClassManager(SubClassA a, SubClassB b, SubClassC c.... and so on) {
return new ClassManager(a, b, c...and so on);
}
I haven't found so far a better solution on how to do this injection with Dagger, but I do need that this ClassManager has access to all of the classes that extend from ParentClass. Is there any other better way? Maybe with other library?
You can use dagger multibindings and bind your subclasses into set, like this
#Module
public abstract class SubClassModule {
#Binds
#IntoSet
public abstract ParentClass bindsSubClassA(impl: SubClassA);
#Binds
#IntoSet
public abstract ParentClass bindsSubClassB(impl: SubClassB)
}
And in module with class manager pass set into constructor
#Provides
#Singleton
public ClassManager provideClassManager(Set<ParentClass> set) {
return new ClassManager(set);
}
I am trying to use hk2 dependency injection in jersey application. I have a class named ClassA implements IClassA interface. I want to use dependency injection for ClassB object in ClassA :
package com.example.test
public class ClassA implements IClassA {
#Inject
ClassB classB;
#Override
public void method() {
classB.doSomething();
}
}
ClassB :
package com.example.test
public class ClassB {
public void doSomething() {
}
}
I created ResourceConfig class.
package com.example.test.di
public class App extends ResourceConfig {
public App() {
register(new MyApplicationBinder());
packages(true, new String[]{"com.example.test"});
}
}
I created AbstractBinder class.
package com.example.test.di
public class MyApplicationBinder extends AbstractBinder {
#Override
protected void configure() {
bind(ClassB.class).to(ClassB.class).in(Singleton.class);
}
}
I addded Application to web.xml
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.example.test.di.App</param-value>
</init-param>
I created ClassA object like this :
IClassA classA = new ClassA();
classA.method(); //--> classB is null
My problem is classB object is always null in ClassA. I cannot find what is wrong.
Thanks.
You have bound ClassB in the Singleton scope (which means hk2 will only create one of them). Instead, bind ClassB into the PerLookup scope. Then also inject a javax.inject.Provider. Every time you call the get method of Provider you should get a new instance of ClassB
I want to use Dagger in a project currently configured with Guice. I'm still very new to the concepts of DI, but I see that both Guice and Dagger use #Inject and #Provides notations. I have some understanding of the #Module and #Component annotations and how to set them up, but I'm wondering if the #Inject and and #Provides can basically be left as they are?
For example, let's say I have this in Guice:
public class ModuleA extends AbstractModule {
#Inject
public ModuleA() {
...
}
#Provides
#Singleton
protected InterfaceX() {
...
}
}
Could the following dagger implementation work the same, assuming there is also a component etc?
#Module
public class ModuleA {
#Inject
public ModuleA() {
...
}
#Provides
#Singleton
protected InterfaceX() {
...
}
}
One thing that confused me was that #Provides is used in Dagger to bind implementations to interfaces, and I'm not sure if that's what it is used for in Guice.
Again, I'm pretty new to this so any clarification would be really appreciated. Thanks!
NOTE: Have not used Dagger but can clarify on Guice side.
#Provides in Guice is for informing the Guice injector about which method to use to for creating the asked object at build time.
for eg : class Parent has implementation in 2 sub classes Child1 and Child2
Now you want to have a logic which defines when to inject Child1 and when to inject child2. This logic can be written in a method which can become the provider for Parent class impl. and to declare this provider method, #Provides annotation is used
class Parent {}
class Child1 extends Parent {}
class child2 extends Parent {}
GuieModule {
#Provides
Parent getParent() {
if(something)
return new Child1();
else
return new child2();
}
}
I'm very new to Guice, but I have a singleton that I believe would normally be created thusly:
#Provides
#Singleton
private SomeClass getSomeClass()
{
return someClassFactory(configuration);
}
However, I want this to be eagerly initialized. When I remove the #Singleton annotation and try to bind(SomeClass.class).asEagerSingleton() I get errors:
1) No implementation for SomeClass was bound.
2) A binding to SomeClass was already configured
How can I provide an Eagerly initialized singleton that is constructed with parameters or a factory?
The #Provides annotation is a separate way to configure a binding for SomeClass; it's conflicting with the bind(SomeClass.class).asEagerSingleton() binding.
To fix it, you'll need to write an explicit provider class and bind it using toProvider:
class MyModule extends AbstractModule {
private static class MyProvider implements Provider<SomeClass> {
private final OtherStuff otherStuff;
#Inject
MyProvider(OtherStuff otherStuff) {
// Inject constructor params if your #Provides method took arguments
this.otherStuff = otherStuff;
}
public SomeClass get() {
return new SomeClass(otherStuff);
}
}
protected void configure() {
bind(SomeClass.class).toProvider(MyProvider.class).asEagerSingleton();
}
}
I need to get prototype class from singleton. I found that method injection is the way to go, but I don't really know how to use spring #Lookup annotation.
I'm new to dependency-injection, and I chose to go with annotation configuration, so I would like to continue in that direction.
I found out that #Lookup annotation was added only recently (https://spring.io/blog/2014/09/04/spring-framework-4-1-ga-is-here), but I cannot find anywhere how to use it.
So, here is simplified example
Configuration class:
#Configuration
#Lazy
public class ApplicationConfiguration implements ApplicationConfigurationInterface {
#Bean
public MyClass1 myClass1() {
return new ContentHolderTabPaneController();
}
#Bean
#Scope("prototype")
public MyClass2 myClass2() {
return new SidebarQuickMenuController();
}
}
And here is class example:
public class MyClass1 {
doSomething() {
myClass2();
}
//I want this method to return MyClass2 prototype
public MyClass2 myClass2(){
}
}
How do I do that with #Lookup annotation?
Before applying #Lookup annotation to your public MyClass2 myClass2() method, read this in #Lookup's Javadoc:
the container will generate runtime subclasses of the method's containing class via CGLIB, which is why such lookup methods can only work on beans that the container instantiates through regular constructors (i.e. lookup methods cannot get replaced on beans returned from factory methods where we can't dynamically provide a subclass for them).
So remove the following factory method style bean declaration from ApplicationConfiguration:
#Bean
public MyClass1 myClass1() {
return new ContentHolderTabPaneController();
}
and add #Component annotation to let Spring instantiate the bean (also add the #Lookup annotation to the method):
#Component
public class MyClass1 {
doSomething() {
myClass2();
}
//I want this method to return MyClass2 prototype
#Lookup
public MyClass2 myClass2(){
return null; // This implementation will be overridden by dynamically generated subclass
}
}
Now get myClass1 bean out of context, and its myClass2 method should have been replaced/overridden to get a new prototype bean each time.
Update:
Using factory method declaration
It's not hard to implement the #Lookup annotated method (the "lookup method"). Without #Lookup and keeping your configuration class unchanged, now MyClass1 looks like (in fact Spring generates a similar implementation in a subclass if #Lookup were used):
public class MyClass1 {
doSomething() {
myClass2();
}
//I want this method to return MyClass2 prototype
#Autowired
private ApplicationContext applicationContext;
public MyClass2 myClass2() {
return applicationContext.getBean(MyClass2.class);
}
}
Spring injects the ApplicationContext for you.
If you are not on Spring 4.1 you can use the provider injection instead:
public class MyClass1 {
#Autowired
private Provider<MyClass2> myClass2Provider;
doSomething() {
MyClass2 myClass2 = myClass2();
myClass2.fooBar()
}
public MyClass2 myClass2(){
return myClass2Provider.get();
}
}
This is DI, IoC, avoids abstract classes and xml definitions for lookup methods.
Also, you can declare myClass2 bean with TARGET_CLASS proxyMode.
#Bean
#Scope("prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
public MyClass2 myClass2() {
return new SidebarQuickMenuController();
}