I have a simple POJO:
public class MyPOJO {
@Inject
private Fizz fizz;
private Buzz buzz;
// rest of class omitted for brevity
}
I would like to configure my Guice module such that there are two types of Fizz
es that it injects:
Fizz
instance; andFizz
instancesI want MyPOJO
to be injected with the special/singleton instance. So I modified my code:
public class MyPOJO {
@Inject @Named("Special-Fizz")
private Fizz fizz;
private Buzz buzz;
// rest of class omitted for brevity
}
Then in my module:
public class MyModule extends AbstractModule {
@Override
public void configure() {
bind(Fizz.class).annotatedWith(
Names.named("Special-Fizz"))
.to(Fizz.class);
// Other bindings here...
}
@Provides @Singleton
private Fizz providesFizz() {
return new Fizz(true, "Special", 12.0);
}
}
But when I try to unit test (JUnit 4.10) this:
public class MyTest {
@Named("Special-Fizz") private Fizz specialFizz;
@Test
public void usingNamedShouldInjectSpecialFizz() {
MyModule mod = new MyModule();
Injector injector = Guice.createInjector(mod);
specialFizz = injector.getInstance(Fizz.class);
Assert.assertTrue(specialFizz != null);
}
}
This passes. So far, so good. But then if I change the name of the specialFizz
field:
@Named("Special-Fuzz-This-Shouldnt-Work") private Fizz specialFizz;
And re-run the test, it still passes. Why?!? Where am I going astray here? Thanks in advance.
Annotation Type SingletonApply this to implementation classes when you want only one instance (per Injector ) to be reused for all injections for that binding.
Note that the only Guice-specific code in the above is the @Inject annotation. This annotation marks an injection point. Guice will attempt to reconcile the dependencies implied by the annotated constructor, method, or field.
The implementation is very easy to understand. We need to create Injector object using Guice class createInjector() method where we pass our injector class implementation object. Then we use injector to initialize our consumer class. If we run above class, it will produce following output.
Annotation Type Inject. @Target(value={METHOD,CONSTRUCTOR,FIELD}) @Retention(value=RUNTIME) @Documented public @interface Inject. Annotates members of your implementation class (constructors, methods and fields) into which the Injector should inject values.
Very odd. Guice should complain if it can't find a Named
binding that it's injecting. I'm a bit confused by your test, though. I don't know what injector.inject
does. Do you mean injectMembers
? It might make more sense to actually get an instance of your POJO and make sure that it's working the way you expect. Maybe something like:
public class FizzTest {
public static class MyModule extends AbstractModule {
@Override
protected void configure() {
}
@Provides
@Singleton
@Named("Special-Fizz")
public Fizz providesFizz() {
return new Fizz(true);
}
}
public static class Fizz {
boolean special = false;
public Fizz() {}
public Fizz(boolean special) {
this.special = special;
}
}
public static class MyPOJO {
@Inject @Named("Special-Fizz")
private Fizz fizz;
@Inject
private Fizz otherFizz;
}
@Test
public void test() {
MyModule mod = new MyModule();
Injector injector = Guice.createInjector(mod);
MyPOJO pojo = injector.getInstance(MyPOJO.class);
assertTrue(pojo.fizz.special);
assertTrue(!pojo.otherFizz.special);
}
}
Guice sees the @Provides
method and happily uses that to inject the Fizz
. If you want to have a special instance of Fizz
, you can drop the annotations from the providesFizz()
method and instead bind with
bind(Fizz.class)
.annotatedWith(Names.named("Special-Fizz")
.toInstance(providesFizz());
This way, you tell Guice exactly which Fizz
to use as the "Special-Fizz", while still letting it inject Fizz
"normally" otherwise.
Disclaimer: I haven't actually tried a setup like yours, but I have used one similar. Let me know if it works or not.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With