Equivalent for #Conditional in CDI - java

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

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.

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.

How to inject indexed (and class specific) strings using Guice

I've been hacking with Google Guice a bit lately and I came up with an idea to inject a String to a constructor according to the class it is being declared in and other several parameters defined in an annotation. For example:
If I define a new qualifier annotation #NamedInjectable to be used by Guice:
#Documented
#Retention(RetentionPolicy.RUNTIME)
#Target({ ElementType.FIELD, ElementType.PARAMETER })
#Qualifier
public #interface NamedInjectable
{
String name() default "";
boolean indexed() default true;
}
Where name is a new name base for the string (default is only the class' name), and indexed states whether or not the name should be incremented each time a new string is being injected.
e.g.
public MyClass {
#Inject
public MyClass(#NamedInjectable(name = "foo", indexed = true) String name) {
// some code
}
}
And name param should be given a value such as "
I considered using Provider Bindings or AssistedInject but I could get it done. One main reason to failing, is somehow getting the name of the class.
Do you have any other idea?
There's no built-in way to customize a standard Guice binding based on names. If you want to stick to Guice alone, you'll probably need Custom Injections.
In addition to the standard #Inject-driven injections, Guice includes hooks for custom injections. This enables Guice to host other frameworks that have their own injection semantics or annotations. Most developers won't use custom injections directly; but they may see their use in extensions and third-party libraries. Each custom injection requires a type listener, an injection listener, and registration of each.
Guice's documentation example for Custom Injections demonstrates a logger instance customized with the type of the injecting class, which sounds very much like something you want to do—it's no more difficult to read the parameters of the annotation you create from within your TypeListener. However, this doesn't work directly with #Inject annotations or constructors, so you may have trouble if you're trying to make the injection happen entirely behind the scenes.
Another option is much simpler: Just use a factory and pass in the newly-constructed class.
public MyClass {
private final String name;
#Inject
public MyClass(NameInjector nameInjector) {
this.name = nameInjector.get(this, "foo", true);
}
}
For ordinary Guice injections, you can't access the name of the class where the something is being injected. If you really need to do that, you would need to use custom injection.
By using a custom TypeListener, you can listen for injection events and know the class that is being injected. On hearing an injection event, you can register a custom MembersInjector that Guice will invoke after it finishes its own injections. This MembersInjector has access to the fully-constructed instance of the class, so it can reflect on fields and inspect annotations. However, it obviously can't inject constructor parameters, since the object has already been created.
In short, there is no way to do custom injection of constructor parameters. But the idea you describe is very possible for field injection!
How to do it
First, you need to register a TypeListener (this code based on the linked Guice wiki page):
public class NamedStringListener implements TypeListener {
public <T> void hear(TypeLiteral<T> typeLiteral, TypeEncounter<T> typeEncounter) {
Class<?> clazz = typeLiteral.getRawType();
while (clazz != null) {
for (Field field : clazz.getDeclaredFields()) {
if (field.getType() == String.class &&
field.isAnnotationPresent(NamedInjectable.class)) {
Annotation annotation = field.getAnnotation(NamedInjectable.class);
// How you create and configure this provider is up to you.
Provider<String> provider = new MyStringProvider(clazz, annotation);
typeEncounter.register(new MyMembersInjector<T>(field, provider));
}
}
clazz = clazz.getSuperclass();
}
}
}
Then, inside MyMembersInjector<T>:
public class MyMembersInjector<T> implements MembersInjector<T> {
final Field field;
final Provider<String> provider;
NamedMembersInjector(Provider<String> provider) {
this.field = field;
this.provider = provider;
this.field.setAccessible(true);
}
public void injectMembers(T t) {
field.set(t, provider.get());
}
}
I leave the implementation of MyStringProvider up to you.
See the Guice CustomInjections wiki page for more.

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.

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