Java: How to get SubClasses in Provider in Dependency Injection - java

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.

Related

#Inject on no-args public method

While reviewing some code I have noticed a POJO (without scope -> #Dependant) which is injected (#Inject) in another bean and that do inject a bean (a field).
But it has also an #Inject annotation on a no-args public method that does initialisations stuff. I thought injection points only happen on field, constructor and setter
public class MyImpl implements MyInterface {
#Inject
private ParamDao paramDao;
private Map<String,List<MyRateDto>> params;
#Inject
public void loadRates() {
params = paramDao....;
}
...
}
To me this method (loadRates) should have been annotated as #PostConstruct. But I was wondering what happen in such case?
I guess the method is simply called after bean creation and field injection... But I have not read anything about it in the spec or elsewhere.
Is it the expected behavior?
Environment: Java 8/JavaEE 7 that targets a JBoss EAP 7.
Thanks
Thanks to #Andreas I have been steered in the right direction.
Looking at the Javadoc of #Inject: "Constructors are injected first, followed by fields, and then methods. Fields and methods in superclasses are injected before those in subclasses. Ordering of injection among fields and among methods in the same class is not specified. --- Injectable methods [...] accept zero or more dependencies as arguments."
So, there is no explicit description for zero arguments. But it's just that #Inject methods are called in arbitrary order, and arguments are resolved.
No argument = nothing to resolve.

Guice: Creating objects by methods

Suppose I have two similar (but different) methods (or maybe static methods) create_x() and create_y() to create objects (call them x and y) both (of class derived) of class Parser.
Now I want to bind the objects created by these two methods like as in answer to my previous question:
bind(Parser.class)
.annotatedWith(Names.named("x"))
.to(ParserXImplementation.class);
bind(Parser.class)
.annotatedWith(Names.named("y"))
.to(ParserYImplementation.class);
but with object created by create_x(), create_y() instead of instances of classes ParserXImplementation, ParserYImplementation. (So that there is no necessity to create classes ParserXImplementation, ParserYImplementation.)
Note that I want the objects to be singletons.
I want the answers both for the case if create_x(), create_y() are static methods and for the case if they are instance methods. If they are instance methods, the class containing them may itself be subject to dependency injection.
How to do this? (injecting dependencies to instances created by methods)
From https://github.com/google/guice/wiki/ProvidesMethods:
When you need code to create an object, use an #Provides method. The method must be defined within a module, and it must have an #Provides annotation. The method's return type is the bound type. Whenever the injector needs an instance of that type, it will invoke the method.
public class BillingModule extends AbstractModule {
#Override
protected void configure() {
...
}
#Provides
TransactionLog provideTransactionLog() {
DatabaseTransactionLog transactionLog = new DatabaseTransactionLog();
transactionLog.setJdbcUrl("jdbc:mysql://localhost/pizza");
transactionLog.setThreadPoolSize(30);
return transactionLog;
}
}
Further, it says that it can use annotation like #Named("x") and #Named("y") to differentiate x and y as described in the answer to Binding the same interface twice (Guice).
This is what I need (however the method is defined inside a module rather than in an arbitrary class).

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();
}

GUICE - at runtime decide on object graph

I'm reviewing Guice. Let's say I've got the following setup:
public interface IsEmailer {...}
public interface IsSpellChecker {...}
public class Emailer implements IsEmailer {
#Inject
public class Emailer(final IsSpellChecker spellChecker)....
}
public class FrenchSpellChecker implements IsSpellChecker {....}
public class EnglishSpellChecker implements IsSpellChecker {....}
#BindingAnnotation public #interface English {}
#BindingAnnotation public #interface French {}
Then in my module I've bound the interfaces to their respective implementations, and annotated the spell checkers with the respective binding-annotation.
Now, let's say based on a runtime variable I need to construct an emailer that either uses the English or the French spell checker.
I thought of using a named providers in my module:
#Provides
#English
IsEmailer provideEnglishEmailer() {
return new Emailer(new EnglishSpellChecker());
}
#Provides
#French
IsEmailer provideFrenchEmailer() {
return new Emailer(new FrenchSpellChecker());
}
This works like this:
IsEmailer emailer = myModule.getInstance(Key.get(IsEmailer.class,
French.class));
Is this the cleanest way to do something like this? After all, I'm forced to construct the object by hand (in the providers).
Thanks
First some notes:
Generally you want to avoid using getInstance as much as possible, except for your "root" element (e.g. YourApplication). Within anything that Guice provides, your best bet is to ask for an injection of Provider<IsEmailer>, or perhaps #English Provider<IsEmailer> and #French Provider<IsEmailer>. Guice will not actually create the elements until you call get on the Provider, so the overhead of creating the Provider is very very light.
You don't have to bind to a provider to get a provider. Guice will resolve any binding of X, Provider<X>, or #Provides X to any injection of X or Provider<X> automatically and transparently.
Provider implementations can take injected parameters, as can #Provides methods.
If you want to bind a lot of things to #English or #French, you may also investigate private modules, since this sounds like the "robot legs" problem to me.
The easiest way is simply to go with the first bullet and inject a Provider of each, especially if you're only doing this once.
You can also bind it in a Module, if your runtime variable is accessible via Guice. Put this in your module along with the #Provides annotations above. (As noted, you may want to rewrite them to accept an EnglishSpellChecker and FrenchSpellChecker as parameters respectively, to enable the spell checkers to inject their own dependencies.)
#Provides IsEmailer provideEmailer(Settings settings,
#English Provider<IsEmailer> englishEmailer,
#French Provider<IsEmailer> frenchEmailer) {
if (settings.isEnglish()) {
return englishEmailer.get();
} else {
return frenchEmailer.get();
}
}
You could use a MapBinder. That would allow you to inject a Map<Language, IsSpellChecker>, and then retrieve the appropriate spell checker at runtime.

Guice Inject Field in class not created by Guice

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));

Categories