Guice Inject Field in class not created by Guice - java

I have a class like so, that I create myself somewhere in my code:
class StarryEyes {
#Inject MyValidator validator;
public StarryEyes(String name) {
//..
}
public doSomething() {
// validator is NULL
}
}
I want Guice to inject an instance of validator, which has a #Singleton annotation.
I have a module that's loaded at startup and it contains the line:
bind(MyValidator.class);
However, it doesn't seem to work as "validator" is always null. I've tried a number of variations like:
bind(MyValidator.class)toInstance(new MyValidator());
or other things like that. Is this not how Guice is supposed to work?

Typically Guice needs to create objects to inject them. If you just call new StarryEyes(name), Guice isn't ever going to see that object so it won't be able to inject it. One thing you can do is to call injector.injectMembers(obj) on the object after you've created it. I wouldn't recommend that, though, as you should avoid referencing the injector in your code.
What you really probably want here is Assisted Inject. With Assisted Inject, you'd declare the constructor for your class something like this:
#Inject public StarryEyes(MyValidator validator, #Assisted String name)
What that means is that validator is a parameter that Guice should inject, while name must be "assisted" (that is, provided at the time the instance is created).
You then create an interface like this:
public interface StarryEyesFactory {
StarryEyes create(String name);
}
With Assisted Inject, Guice can then implement that factory for you. You bind it like this:
bind(StarryEyesFactory.class).toProvider(
FactoryProvider.newFactory(StarryEyesFactory.class, StarryEyes.class));
You then inject a StarryEyesFactory anywhere you want to create an instance of it. Where you would have called new StarryEyes(name) previously, you now call starryEyesFactory.create(name) instead. When you call create(name) on the factory, it will take the name and pass it to the constructor and provide the bound validator itself.
Starting in Guice 3, you do this using a FactoryModuleBuilder:
install(new FactoryModuleBuilder().build(StarryEyesFactory.class));

Related

Java: How to get SubClasses in Provider in Dependency Injection

Given 3 classes: FooA, FooB and FooC, which are all subclasses of the abstract class Foo. However, all are using the same constructor with Dependency Injection, so I am using javax.inject.Provider to get fully injected instances of the subclasses.
Provider<FooA> fooAProvider
Provider<FooB> fooBProvider
Provider<FooC> fooCProvider
How can I sum the Providers up to become a Provider<Foo> fooProvider, while still being able to get instances of its subclass or is there another way to get rid of the multiple Provider?
You can combine a producer and qualifiers to distinguish resolved instances:
public class ProviderSuppliers {
#Producer
#Named("fooA")
public static Provider<Foo> getFooA() {
return //create Provider for FooA
}
#Producer
#Named("fooB")
public static Provider<Foo> getFooB() {
return //create Provider for FooB
}
#Producer
#Named("fooC")
public static Provider<Foo> getFooC() {
return //create Provider for FooC
}
}
Then you can inject them using the qualifier:
#Inject
#Named("fooA")
Provider<FooA> fooAProvider
#Inject
#Named("fooB")
Provider<FooB> fooBProvider
//and so on
Now, on Provider<Foo>: this is a little problematic because you technically can't do this:
Provider<Foo> fooA = new Provider<FooA>(); //you can't assign like this.
However, you can still declare as below and still get it to work by injecting the expected instance (the qualifier takes care of that)
#Inject
#Named("fooA")
Provider<Foo> fooAProvider
This is practically bad as you're simply going around type safety. The better approach would be to just have the same type declared on producer and at injection point, which also helps with type safety where Provider<FooX> objects are actually used.

Eclipse RCP - Injecting interfaces marked with #Singleton

I have the following code:
public interface DummyInterface {
}
and
#Singleton
#Creatable
public class DummyInterfaceImpl1 implements DummyInterface {
}
And when I want I can simply inject this, and it works just fine, (see below):
#Inject
DummyInterfaceImpl1
However I can't do
#Inject
DummyInterface
Because I get an
Unable to process "ClassWhereIInject.dummyInterface": no actual value was found for the argument "DummyInterface".
So, I am trying to understand, if I use the combination of #Creatable and #Singleon, without adding the instance that I want to inject in the IEclipseContext, then I can only inject implementation classes and not interfaces?
I can see how this can get problematic, especially when one has multiple implementation classes for the same interface, and the dependency injection framework doesn't know which to inject...that is if you don't use the #Named annotation to specify...
The injection system only looks for something with the name you specify. It does not try and find a class that happens to implement that interface. So no you can't use an #Creatable class with a different name to the interface.
An alternative is to use a 'ContextFunction'. This is a function which is called when the injection system is looking for a name. The context function can create an instance of something suitable and put it in the context for the injector. Full details on context function are here

Equivalent for #Conditional in CDI

I have two classes with post construct initialization, and i need one of them to be injected based on a vm argument. I have done this kind of conditional injection in spring using #Conditional annotation, however i could not find any equivalent in CDI. Can some one please help me with this.
The code goes something like this,
public void impl1{
#PostConstruct
public void init(){
....
}
....
}
public void impl2{
#PostConstruct
public void init(){
...
}
....
}
If vmargument type=1, impl1 has to be injected and if type=2, impl2 has to be injected
For runtime decision (without changing your beans.xml), you basically have two options:
Option 1: use a producer method
#Produces
public MyInterface getImplementation() {
if(runtimeTestPointsTo1) return new Impl1();
else return new Impl2();
}
Drawback: you leave the world of bean creation by using new, therefore your Impl1 and Impl2 cannot #Inject dependencies. (Or you inject both variants in the producer bean and return one of them - but this means both types will be initialized.)
Option 2: use a CDI-extension
Basically listen to processAnotated() and veto everything you don't want. Excellent blog-entry here: http://nightspawn.com/rants/cdi-alternatives-at-runtime/
Probably the best way is to use an extension. You will create two classes both of which will have the same type so they are eligible for injection into the same injection point. Then, using the extension, you will disable one of them, leaving only one valid (the other will not become a bean).
Extensions can 'hook into' container lifecycle and affect it. You will want to leverage ProcessAnnotatedType<T> lifecycle phase (one of the first phases) to tell CDI that certain class should be #Vetoed. That means CDI will ignore it and not turn in into a bean.
Note the type parameter T in ProcessAnnotatedType<T> - replace it with a type of your implementation. Then the observer will only be notified once, when that class is picked up by CDI. Alternatively, you can replace T with some type both impls have in common (typically an interface) and the observer will be notified for both (you then need to add a login to determine which class was it notified for).
Here is a snippet using two observers. Each of them will be notified only once - when CDI picks up that given impl - and if it differes from the vm arg, it is vetoed:
public class MyExtension implements Extension {
public void observePAT(#Observes ProcessAnnotatedType<Impl1.class> pat){
// resolve your configuration option, you can alternatively place this login into no-args constructor and re-use
String vmArgumentType = loadVmArg();
// if the arg does not equal this impl, we do not want it
if (! vmArgumentType.equals(Impl1.class.getSimpleName())) {
pat.veto();
}
}
public void observePAT(#Observes ProcessAnnotatedType<Impl2.class> pat){
// resolve your configuration option, you can alternatively place this login into no-args constructor and re-use
String vmArgumentType = loadVmArg();
// if the arg does not equal this impl, we do not want it
if (! vmArgumentType.equals(Impl2.class.getSimpleName())) {
pat.veto();
}
}
}
Create your own #Qualifier and use it to inject cdi bean:
public class YourBean {
#Inject
#MyOwnQualifier
private BeanInterface myEJB;
}
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.FIELD, ElementType.METHOD})
public #interface MyOwnQualifier {
YourCondition condition();
}

Dagger 2: When to use constructor injections and when to use field injections?

I was kind of lazy and used to use almost entirely field injections. I was just providing empty constructor, put my #Inject fields I everything was looking nice and simple. However field injection have its trade-offs so I've devised some simple rules that help me to decide when to used field and when to use constructor injections. I will appreciate any feedback if there is mistake in my logic or if you have additional considerations to add.
First some clarification in order to be on the same page:
Constructor injection:
#Inject
public SomeClass(#Named("app version") String appVersion,
AppPrefs appPrefs) {...
Same with the field injection:
public class SomeClass {
#Inject
#Named("app version") String mAppVersion;
#Inject
AppPrefs appPrefs;
Rule 1: MUST use field injection if I don't control creation of the object (think Activity or Fragment in Android). If some (non-dagger aware) framework is creating my object and handles it to me I have no choice but to inject it manually after I receive the instance.
Rule 2: MUST use constructor injection if the class is/may be used in another project that does not use Dagger 2. If the other project(s) do not use Dagger they cannot use DI so the user have to create the object the "old" way using new.
Rule 3: PREFER constructor injection when working with class hierarchies because it is easier to create unit tests.
Clarification:
Considering the following structure that uses field injection:
package superclass;
public class SuperClass {
#Inject
HttpClient mHttpClient;
...
}
.
package differentpackage;
public class SubClass extends SuperClass {
public SubClass() {
}
}
When I am creating unit test for SubClass in directory test/java/differentpackage I have no choice but to bring up the entire DI infrastructure in order to be able to inject the HttpClient. In contrast, if I was using constructor injection like this:
public class SuperClass {
private final HttpClient mHttpClient;
#Inject
public SuperClass(HttpClient httpClient) {
mHttpClient = httpClient;
}
}
in my unit test I could simply:
HttpClient mockHttp = mock(HttpClient.class);
Subclass tested = new Subclass(mockHttp);
// tests
So basically now I am in the other extreme: I tend to rely mostly on constructor injections and use field injections only when 'Rule 1' applies.
The only 'problem' that I have with the constructor injects is that for 'end' classes constructors sometimes become quite overloaded with parameters and they look verbose and ugly like this:
#Inject
public ModelMainImpl(#Named("app version") String appVersion,
AppPrefs appPrefs,
LoginPrefs loginPrefs,
#ForApplication Context appContext,
NetworkInfoProvider networkInfoProvider,
AndroidEventPoster androidEventPoster,
Session session,
ForgeExchangeManager exchangeManager,
HttpFunctionality httpFunctionality,
#Named("base url") String baseUrl,
#Named("forge result producer") ResultProducer<ForgeExchangeResult> resultProducer
) {
Guys, what are your rules to choose between constructor and field injects? I am missing something, are there errors in my logic?
Use constructor injection. if you can't, use property injection.
Rule 1 seems ok, like decorations or attributes you can use Property(field) injection.
Rule 2 seems ok, because who uses your class they have to follow your constructor. They may not know they have to intilaize your property also.
Rule 3 It's not just good for unit test. It's good for applying Single Responsibilty. It's easier to see your object graph.Otherwise you will hide it with property.
If we come in your question, yes there a lot of parameters in your constructor. But the solution is not property injection. You can refactor your code and use aggregate services

How to use Google Guice to create objects that require parameters?

Maybe I am just blind, but I do not see how to use Guice (just starting with it) to replace the new call in this method:
public boolean myMethod(String anInputValue) {
Processor proc = new ProcessorImpl(anInputValue);
return proc.isEnabled();
}
For testing there might be a different implementation of the Processor, so I'd like to avoid the new call and in the course of that get rid of the dependency on the implementation.
If my class could just remember an instance of Processor I could inject it via the constructor, but as the Processors are designed to be immutable I need a new one every time.
How would I go about and achieve that with Guice (2.0) ?
There is some time since I used Guice now, but I remember something called "assisted injection". It allows you to define a factory method where some parameters are supplied and some are injected. Instead of injecting the Processor you inject a processor factory, that has a factory method that takes the anInputValue parameter.
I point you to the javadoc of the FactoryProvider. I believe it should be usable for you.
You can get the effect you want by injecting a "Provider", which can by asked at runtime to give you a Processor. Providers provide a way to defer the construction of an object until requested.
They're covered in the Guice Docs here and here.
The provider will look something like
public class ProcessorProvider implements Provider<Processor> {
public Processor get() {
// construct and return a Processor
}
}
Since Providers are constructed and injected by Guice, they can themselves have bits injected.
Your code will look something like
#Inject
public MyClass(ProcessorProvider processorProvider) {
this.processorProvider = processorProvider;
}
public boolean myMethod(String anInputValue) {
return processorProvider.get().isEnabled(anInputValue);
}
Does your Processor need access to anInputValue for its entire lifecycle? If not, could the value be passed in for the method call you're using, something like:
#Inject
public MyClass(Processor processor) {
this.processor = processor;
}
public boolean myMethod(String anInputValue) {
return processor.isEnabled(anInputValue);
}

Categories