So basicly am trying to use dagger to inject a Baz field into class Foo, it goes like this
Baz.java
public class Baz {
}
Foo.java
public class Foo {
#Inject Baz baz;
}
but nothing gets injected and baz still null when i run it, i even tried to write the Baz empty constructor and annotate it with #Inject but it doesn't work either
how dagger work is it able to see all my classes so when i request a class instance he can create one, or am i missing some annotation, or even worse my annotation processor not working. i added those dependencies to my app.gradle
implementation 'com.google.dagger:dagger:2.14.1'
annotationProcessor 'com.google.dagger:dagger-compiler:2.14.1'
If you want to inject something somewhere using Dagger2, it's essential to have a component, also you need a place, where you want to have Foo object (which has a Baz object itself). In addition to this, you should specify the way, how objects should be created by dagger2. In your case constructor injection is absolutely OK.
Let's assume, that our component is TestComponent and the place, where we want to have Foo object is MainActivity, then the code would be something like this:
Baz.java
public class Baz {
#Inject
public Baz() {
}
}
Foo.java
public class Foo {
#Inject
Baz baz;
#Inject
public Foo() {
}
}
TestComponent.java
#Component
public interface TestComponent {
void inject(MainActivity injector);
}
(When you create component, rebuild the project)
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Inject
Foo foo;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerTestComponent.builder().build().inject(this);
}
}
Related
I spent a plenty of time for finding any answers, but I think I have to ask.
I'm using Weld-SE for testing my entities.
I prepared entity randomizer for testing.
abstract class BaseEntityRandomizer<T extends BaseEntity>
implements Randomizer<T> {
#Override public T getRandomValue() {
...
}
}
class MySomeOtherEntityRandomizer
extends BaseEntityRandomizer<MySomeOther> {
#Override public MySomeOther getRandomValue() {
...
}
}
Now, with my test class, I want to inject those randomizers which each matches generic parameters
#ExtendWith(WeldJunit5Extension.class)
#AddPackages({BaseEntityRandomizer.class})
abstract class BaseEntityTest<T extends BaseEntity> {
#Test void doSome() {
}
#Inject
private BaseEntityRandomizer<T> entityRandomizer;
}
class MySomeOtherTest extends BaseEntityTest<MySomeOther> {
...
// I expect an instance of MySomeOtherRandomizer in injected
// into the entityRandomizer field.
}
Subclasses of randomizers and tests are prepared.
But I failed to make it work.
How can I make it work?
I tried with following factory class
class BaseEntityRandomizerFactory {
#Produces
public BaseEntityRandomizer<MySome> produceMySomeRandomizer() {
return new MySomeRandomizer();
}
}
I got
org.jboss.weld.exceptions.IllegalArgumentException:
WELD-001408: Unsatisfied dependencies for type BaseEntityRandomizer<T extends BaseEntity> with qualifiers #Default
at injection point [BackedAnnotatedField] #Inject protected transient ....BaseEntityTest.entityRandomizer
at ....BaseEntityTest.entityRandomizer(BaseEntityTest.java:0)
One way to achieve this is to use CDI Programmatic lookup. In your case, I'd start with #Inject Instance<Object> and then you can use subsequent calls to select() and get() methods to pick up whichever bean you desire. Usage looks something like this (assumes existence of beans with types Foo, Bar and List<String>):
#Inject
private Instance<Object> instance;
#Test void doSome() {
// selecting and obtaining instances of beans
Foo foo = entityRandomizer.select(Foo.class).get();
Bar bar = entityRandomizer.select(Bar.class).get();
// in case you need to select a parameterized type from instance, use TypeLiteral
List<String> listBean = entityRandomized..select( new TypeLiteral<List<String>>(){}).get()
}
I'm developing upon a java core library were change is held to a minimum, it holds a class Foo, where Foo is used by a spring rest interface and autowired into the rest interface.
I have to extend Foo to override one of it's method that is called upon Foo.init(), to alter the initiation a bit.
My FooExtend is autowired from another class in my project, and I'm hoping to get these two to reference the same object, the FooExtend object, but at the moment I get one Foo object and one FooExtend. How should I solve this? Examples below
#Component
public class Foo{
#PostConstruct
private void init() {
startStuff();
}
protected void startStuff(){
//Stuff done here
}
}
#Component
public class FooExtend extends Foo{
#PostConstruct
private void init() {
//Nothing is done here
}
#Override
protected void startStuff(){
//Different altered stuff is done here
}
}
Try to exclude the Foo class from scan
#ComponentScan(value = {'your.package.here'}, excludeFilters = {
#ComponentScan.Filter(classes = { Foo.class })
})
There are 2 possible answers depending on your requirements:
1) You want to register both Foo and FooExtend in your Spring context.
In such case you can use #Qualifier annotation to inject one instance or another:
#Autowired
#Qualifier("fooExtend")
Foo foo;
2) You only want to register FooExtend in your Spring context.
#ComponentScan(value = {'your.package.here'}, excludeFilters = {
#ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE, value=Foo.class))
}
However it is required that Foo and FooExtend are in different packages so that FooExtend is NOT exluded by the above filter.
Suppose I have a third party class as follows:
public class MyObject {
#Inject
public MyObject(Foo foo, Bar bar) { ... }
}
Now suppose that I have a factory interface like so:
public interface MyObjectFactory {
public MyObject build(Bar bar);
}
The idea is that I wish to have a MyObjectFactory that builds a MyObject for a fixed Foo - that is, essentially adding in the #Assisted annotation on the Bar constructor parameter from the outside. Of course, manually implementing MyObjectFactory is always possible:
public class MyObjectFactoryImpl implements MyObjectFactory {
#Inject private Provider<Foo> foo;
#Override
public MyObject build(Bar bar) { return new MyObject(foo.get(), bar); }
}
But let's say that there are conditions that require me to have Guice build MyObject instances - for example, method interceptors. This seems like a job for "injecting the injector":
public class MyObjectFactoryImpl implements MyObjectFactory {
#Inject private Injector injector;
#Override
public MyObject build(Bar bar) {
Injector child = injector.createChildInjector(new AbstractModule() {
#Override
protected void configure() {
bind(Bar.class).toInstance(bar);
// Set up method interceptors for MyObject here...
}
});
return child.getInstance(MyObject.class);
}
}
This sounds evil and boiler-plate-y, so I'm wondering if there are any alternate implementations and/or a way to have Guice generate the factory impl.
First of all, it is rare that you want to be passing instances of MyObject around in your class for exactly the reasons you describe. You have no control over them, so you can't add #Assisted annotations, you can't add method interceptors, etc. etc. Plus, what happens when you want to swap out the third party library for a different implementation?
Therefore, you should be wrapping MyObject into another object.
// **Please** choose better names than this in your real code.
public class MyWrapperBackedByMyObject implements MyWrapperInterface {
private final MyObject delegate;
#Inject
MyWrapperObject(Foo foo, #Assisted Bar bar) {
delegate = new MyObject(foo, bar);
}
#NotOnWeekends // Example of how you might do method interception
public void orderPizza() {
delegate.orderPizza();
}
}
Then, remove all references to MyObject throughout your code, using the naming convention I describe above, there should only be references to MyWrapperInterface.
actually it is. Have a look Assisted Inject
Include
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-assistedinject</artifactId>
<version>${guice.version}</version>
</dependency>
Update injection with assisted
public class MyInjectedObject extends MyObject implements MyIntf {
#Inject
public MyObject(Foo foo, #Assisted Bar bar) { super(foo,bar); }
}
You have to add one more interface:
public interface MyIntf {}
In your module bind generic factory to your interface
install(new FactoryModuleBuilder()
.implement(MyIntf.class, MyInjectedObject.class)
.build(MyObjectFactory.class)
);
Now you can inject MyObjectFactory anywhere you want.
MyObject obj = myObjectFactory.build(bar);
Currently testing with dagger, what I want to do is instantiate and inject different Bar implementations. How can I inject fields in provided fields?
for example:
Module:
#Module(
injects = {
Main.class
},
complete = false,
library = true
)
public class ExampleTestModule {
#Provides
public Foo providesFoo() {
return new Foo();
}
#Provides
public Bar providesBar(BarImpl impl) {
// return new BarImpl(); // null
return impl;
}
}
Main:
public class Main {
#Inject
Foo foo;
}
Foo:
public class Foo {
#Inject
Bar bar;
}
Bar:
public interface Bar {
}
BarImpl
public class BarImpl implements Bar {
}
TestCase:
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
public void testFoo() {
Main main = new Main();
ObjectGraph.create(new ExampleTestModule()).inject(main);
assertNotNull(main.foo);
}
public void testFooBar() {
Main main = new Main();
ObjectGraph.create(new ExampleTestModule()).inject(main);
assertNotNull(main.foo.bar);
}
}
Main.Foo is not null but Main.Foo.Bar is null.
You are never injecting bar into foo.
ObjectGraph.create(new ExampleTestModule()).inject(main);
This line will only look at the fields of main which are annotated by #Inject, and inject them. There is no recursive behavior.
Fixing the problem
Let's go step-by-step:
You provided complete = false and library = true in your Module. You should only use these if really necessary. Dagger will give you warnings when something is wrong, and these properties surpress these warnings. For example, removing them raises the following warning when compiling:
Error:(11, 8) error: No injectable members on BarImpl. Do you want to add an injectable constructor? required by providesBar(BarImpl) for ExampleTestModule.
Let's add an empty injectable constructor to BarImpl, as it suggests:
public class BarImpl implements Bar {
#Inject
BarImpl(){
}
}
Compiling will give a new error:
Error:(11, 8) error: Graph validation failed: You have these unused #Provider methods:
1. ExampleTestModule.providesBar()
Set library=true in your module to disable this check.
Apparently, providesBar() is never used. That means, the bar field in Foo will never be injected. You can do two things:
Inject bar manually:
ObjectGraph graph = ObjectGraph.create(new ExampleTestModule());
graph.inject(main);
graph.inject(main.foo);
Use injectable constructors (Preferred option):
public class Foo {
Bar bar;
#Inject
Foo(Bar bar){
this.bar = bar;
}
}
Using the injectable constructor, you will now have a compile error in providesFoo(), since you don't supply a Bar instance in the Foo constructor. The nice thing about Dagger is, you can safely completely remove this method. Since Foo is annotated with #Injectable, everywhere it needs to inject a Foo instance, it uses this constructor. And when it uses this constructor, it notices it needs a Bar instance, and injects this as well.
Finally, we can remove the #Inject annotation from the Foo field in Main, and create an injectable constructor. Using ObjectGraph.get(Class<?>) we can retrieve a fully instantiated Main instance.
The result
The end result should look like this:
Module:
#Module(
injects = Main.class
)
public class ExampleTestModule {
#Provides
public Bar providesBar(BarImpl impl) {
return impl;
}
}
Main:
public class Main {
Foo foo;
#Inject
Main(Foo foo) {
this.foo = foo;
}
}
Foo:
public class Foo {
Bar bar;
#Inject
Foo(Bar bar){
this.bar = bar;
}
}
Bar:
public interface Bar {
}
BarImpl:
public class BarImpl implements Bar {
#Inject
BarImpl(){
}
}
ApplicationTest:
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
public void testFoo() {
Main main = ObjectGraph.create(new ExampleTestModule()).get(Main.class);
assertNotNull(main.foo);
}
public void testFooBar() {
Main main = ObjectGraph.create(new ExampleTestModule()).get(Main.class);
assertNotNull(main.foo.bar);
}
}
Conclusion
From the result, we can conclude some things:
Don't just add library = true and complete = false to your module. This should only be necessary when using multiple complex modules.
Try to use injectable constructors. This is what Dagger's built for, and works best. An extra perk is that you can now have your fields private, like they should be.
When using injectable constructors, you really only need to create providesXXX methods when injecting instances of interfaces, like we did with Bar and BarImpl. Because, hey, that's exactly what Dependency Injection is for, right?
I have the following code using Guice bindings:
public class MyApplication {
public static void main(String[] args) {
Guice.createInjector(new AbstractModule() {
#Override
protected void configure() {
bind(Foo.class).annotatedWith(Names.named("first")).toInstance(new Foo("firstFoo"));
bind(Foo.class).annotatedWith(Names.named("second")).toInstance(new Foo("secondFoo"));
bind(Bar.class).to(BarImpl.class);
bind(MyApplication.class).asEagerSingleton();
}
});
}
private #Named("first") Bar first;
private #Named("second") Bar second;
static #Value class Foo { String name; }
static interface Bar {}
static class BarImpl implements Bar {
#Inject #Named Foo foo;
}
}
I'm trying to get a Bar object for both named Foos injected in my application. Basically, it should somehow connect the #Named on Foo with the one on Bar. I have tried several solutions, from putting #Named on everything to writing a custom Provider. The latter didn't work because I don't have access to the value of the #Named annotation inside the provider. I think the solution is somewhere in the line bind(Bar.class).to(BarImpl.class);, telling it to remember the value of the #Named annotation.
My question is, is this possible at all, and if so, how?
It is using PrivateModules. Basically:
A private module's configuration information is hidden from its environment by default. Only bindings that are explicitly exposed will be available to other modules and to the users of the injector. For more explanation see this FAQ entry.
Here is how you'd use it:
protected void configure() {
install(new PrivateModule() {
#Override
protected void configure() {
// #bind makes bindings internal to this module unlike using AbstractModule
// this binding only applies to bindings inside this module
bind(Foo.class).toInstance(new Foo("first"));
// Bar's foo dependency will use the preceding binding
bind(Bar.class).annotatedWith(Names.named("first")).to(BarImpl.class);
// if we'd stop here, this would be useless
// but the key method here is #expose
// it makes a binding visible outside as if we did AbstractModule#bind
// but the binding that is exposed can use "private" bindings
// in addition to the inherited bindings
expose(Bar.class).annotatedWith(Names.named("first"));
}
});
install(new PrivateModule() {
#Override
protected void configure() {
bind(Foo.class).toInstance(new Foo("second"));
bind(Bar.class).annotatedWith(Names.named("second")).to(BarImpl.class);
expose(Bar.class).annotatedWith(Names.named("second"));
}
});
bind(MyApplication.class).asEagerSingleton();
}
}
Now you effectively have 2 Bars each of which look like
static class BarImpl implements Bar {
#Inject Foo foo;
}
but with the power of PrivateModules have a different implementation bound for the same dependency.
Hope it makes sense.