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.
Related
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);
}
}
In my application there are multiple modules binding something to a specific name or class. Is there a way to tell Guice, which modules it should use when resolving the dependencies to inject.
My simplified dependency graph looks something like this where blue indicates classes from module 1 and red indicates classes from module 2. Now I want to create two instances from the A class, but with different classes bound to some dependencies.
public class Module1 extends AbstractModule {
#Override
protected void configure() {
bind(C.class).to(C_Impl1.class)
bind(D.class).to(D_Impl1.class)
}
}
public class Module2 extends AbstractModule {
#Override
protected void configure() {
bind(C.class).to(C_Impl2.class)
bind(D.class).to(D_Impl2.class)
}
}
public class Application {
#Inject #UseModules(Module1, ...) private final A someClassUsingImpl1;
#Inject #UseModules(Module2, ...) private final A someClassUsingImpl2;
public void doSomethingWithImpl1() {
someClassUsingImpl1.doSomething()
}
public void doSomethingWithImpl2() {
someClassUsingImpl2.doSomething()
}
}
This is the problem private modules were built for. You will still need to use a binding annotation to differentiate whether you're asking for the Impl1 version of A or the Impl2 version of A.
/** Marks Impl1 classes. Inject #Impl1 A to get A using C_Impl1 and D_Impl1. */
#BindingAnnotation
#Retention(RetentionPolicy.RUNTIME)
#interface Impl1 {}
/** Marks Impl2 classes. Inject #Impl2 A to get A using C_Impl2 and D_Impl2. */
#BindingAnnotation
#Retention(RetentionPolicy.RUNTIME)
#interface Impl2 {}
/** This is now a PrivateModule. Only exposed bindings can be used outside. */
public class Module1 extends PrivateModule {
#Override
protected void configure() {
// Bind C and D as you had before.
bind(C.class).to(C_Impl1.class);
bind(D.class).to(D_Impl1.class);
// Here's the tricky part: You're binding "#Impl1 A" to
// "A" without a binding annotation, but only in here.
bind(A.class).annotatedWith(Impl1.class).to(A.class);
// Now you expose #Impl1 A, so it can be used outside.
// As long as A, C, and D are only bound within private modules,
// they won't conflict with one another, and #Impl1 A is unique.
expose(A.class).annotatedWith(Impl1.class);
}
}
/** Treat Module2 the same way, as a private module. */
public class Application {
#Inject #Impl1 private final A someClassUsingImpl1;
#Inject #Impl2 private final A someClassUsingImpl2;
// ...
}
If this is a common pattern for you, create a general PrivateModule that takes in the classes that vary as constructor parameters, so you don't need to repeat yourself. These can be added to the top-level injector, or installed within other modules.
Injector injector = Guice.createInjector(new YourMainModule(),
new ImplModule(Impl1.class, C_Impl1.class, D_Impl1.class),
new ImplModule(Impl2.class, C_Impl2.class, D_Impl2.class));
I'm learning Google Guice. Do you know how to implement the "robot legs" problem? Let me explain this with an example.
Let's say that I have some class called Service:
#Singleton
public class Service {
#Inject
Source source;
}
The interface Source has two implementations:
public class SourceDatabase implements Source {
}
public class SourceFileSystem implements Source {
}
My module is implemented like this:
public class MyModule extends AbstractModule {
#Override
protected void configure() {
bind(Service.class).asEagerSingleton();
}
}
Well, I would like to know if this is possible:
public class MainClass {
#Inject #SomeAnnotation("database")
Service serviceWithADatabaseSource;
#Inject #SomeAnnotation("file-system")
Service serviceWithAFileSystemSource;
}
Does exist some annotation or binding that let me do that, let me annotate a member like serviceWithADatabaseSource, and this helps Guice to know that the internal member source should be injected with the SourceDatabase implementation?
Edit: Thanks to Daniel Martin, for give us the name of this kind of problem on his comment.
As documented in the Guice Wiki, you need to install two PrivateModules, each of which exposes a Service with the right annotation for you.
public class MyModule extends AbstractModule {
#Override
protected void configure() {
install(new PrivateModule() {
#Override public void configure() {
// Bind Source to SourceDatabase.
bind(Source.class).to(SourceDatabase.class);
// Bind #Named("database") Service to Service.
bind(Service.class).annotatedWith(Names.named("database"))
.to(Service.class);
// Now expose #Named("database") Service without exposing
// either of the other two conflicting bindings.
expose(Service.class).annotatedWith(Names.named("database"));
}
});
install(new PrivateModule() {
#Override public void configure() {
// Same as above.
bind(Source.class).to(SourceFileSystem.class);
bind(Service.class).annotatedWith(Names.named("file-system"))
.to(Service.class);
expose(Service.class).annotatedWith(Names.named("file-system"));
}
});
}
}
If the modules were not PrivateModule instances, those bindings to Source and Service would conflict with one another. However, instead, each binding inherits all the public bindings from the Injector but only exposes the #Named(...) Service to the outside world. This way the same Service implementation can inject the same non-annotated Source but have it return different fully-injected types.
Also note that you will not be able to ask for a Source or Service (without an annotation) outside of the PrivateModules, because you haven't established a binding in any non-private Module. This should be expected: The PrivateModule bindings shouldn't conflict with any public bindings, and without entering through one of the PrivateModule's exposed bindings, Guice won't know which Source or Service to return.
Finally, given that Module instances can take constructor parameters, it may be a good idea to extract the two anonymous inner PrivateModules into a named equivalent:
public class MyModule extends AbstractModule {
#Override
protected void configure() {
install(new SourcePrivateModule(SourceDatabase.class, "database"));
install(new SourcePrivateModule(SourceFileSystem.class, "file-system"));
}
}
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?