CDI conditional Bean with Instance<T> - java

I have the necessity to provide the correct Bean implementation at runtime.
The common interface:
public interface MyInterface { ... }
The implementations:
#Named("one")
class MyInterfaceImpl1 implements MyInterface { ... }
#Named("two")
class MyInterfaceImpl2 implements MyInterface { ... }
#Named("three")
class MyInterfaceImpl3 implements MyInterface { ... }
Notice these classes are package-private.
I then wrote a #Produces method:
#Produces
#Singleton
MyInterface getMyInterface(
final Instance<MyInterface> myInterfaceImplementations,
final Configuration configuration) {
// Might be one, two or three.
final String parameter = configuration.getString("value");
return myInterfaceImplementations.select(new NamedLiteral(parameter)).get();
}
Is this the correct way to go, or is there a better solution?

Your solution would work fine, here are my 0.02$ just to make sure you intended it that way:
What Nikos Paraskevopoulos meant in his comment is that your are effectively creating four beans to inject one. MyInterfaceImpl1, MyInterfaceImpl2, MyInterfaceImpl3 are all legitimate beans for injection anywhere in the app. If these beans are heavy, creation may take some time, also the ability to inject them anywhere might not be intended? And then there is your producer method - the fourth bean - which I assume is ultimately the only one you are after.
Secondly, the three implementation beans have different scope from the producer method. If they are eligible for injection, in your case it seems logical that they share same scope perhaps?
Thirdly, using #Singleton. I would also advice for #ApplicationScoped, there is no harm and no overhead by having a proxy. You won't be able to tell the difference and can easily avoid some unpleasant surprises with CDI singleton (which doesn't behave like EJB singleton).

I think a more elegant solution would be to let the CDI do all the magic ;-)
Something like:
import javax.enterprise.inject.spi.CDI;
#Produces
#Singleton
MyInterface getMyInterface(final Configuration configuration) {
// Might be one, two or three.
final String parameter = configuration.getString("value");
Set<MyInterface> candidates = CDI.current().getBeanManager().getBeans(parameter);
return ( candidates.size()>0 ? candidates.get(0) : null);
}
You could also use the alternate signature of getBeans() signature to play with qualifiers when looking for a particular impl of your interface:
cfr https://docs.oracle.com/javaee/7/api/javax/enterprise/inject/spi/BeanManager.html#getBeans-java.lang.reflect.Type-java.lang.annotation.Annotation...-

Related

Java Dependency Injection - Annotation based setup possible in scenario?

I'm fiddling around with Dependency Injection in Java using simple JUnit tests and javax.inject-Annotations.
I have the following scenario: There's a "top-level"-class (SomeObject) with two dependencies (SomeObjDepA and SomeObjDepB). SomeObjDepB has a dependency to SomeObjDepA too. And this should be the same instance of SomeObjDepA as in the SomeObject-instance. But SomeObjDepA must not be a Singleton, since different SomeObj-instances shall have different instances of SomeObjDepA (and SomeObjDepB). This is where I am stuck.
To be more clear, here's some basic code without any configuration:
public class SomeObject {
#Inject
private SomeObjDepA someObjDepA;
#Inject
private SomeObjDepB someObjDepB;
public SomeObjDepA getSomeObjDepA() {
return someObjDepA;
}
public SomeObjDepB getSomeObjDepB() {
return someObjDepB;
}
}
public class SomeObjDepA {
}
public class SomeObjDepB {
#Inject
private SomeObjDepA someObjDepA;
public SomeObjDepA getSomeObjDepA() {
return someObjDepA;
}
}
public class DependencyInjectionTest {
#Inject
private Provider<SomeObject> someObjProvider;
#Test
public void instancesTest() {
final SomeObject someObjInst1 = this.someObjProvider.get();
final SomeObject someObjInst2 = this.someObjProvider.get();
Assertions.assertNotEquals(someObjInst1, someObjInst2);
Assertions.assertNotEquals(someObjInst1.getSomeObjDepA(), someObjInst2.getSomeObjDepA());
Assertions.assertNotEquals(someObjInst1.getSomeObjDepB(), someObjInst2.getSomeObjDepB());
Assertions.assertEquals(someObjInst1.getSomeObjDepA(), someObjInst1.getSomeObjDepB().getSomeObjDepA());
Assertions.assertEquals(someObjInst2.getSomeObjDepA(), someObjInst2.getSomeObjDepB().getSomeObjDepA());
}
}
Question: How to setup dependency injection to build up a scenario like this? I am looking for a annotation or Java based configuration (if possible)
I am currently using CDI 2.0 (Weld 3.1.5), and JUnit 5 for testing. I prefer a solution using CDI, but any other solution using Spring, Guice, etc. would be nice to.
Many thanks in advance
Depending on what you're looking for, you want to make use of scopes and/or qualifiers.
You can think of a scope as a lifespan. If you don't specify a scope (you don't anywhere above), then the default scope is "create a new one whenever one is called for", which is known as dependent scope. (This is because the thing being injected's lifespan is dependent on the thing that is housing it.)
As #Glains points out above, #ApplicationScoped is one way of indicating that a bean should be in "application scope", which is basically singleton scope with extra goodies. So you can put that on any class that meets the requirements to indicate that its lifespan should be that of the application as a whole.
Next, you talk about distinguishing between two otherwise indistinguishable occurrences of a given object, both of which might be singletons (SomeObjDepA). Qualifiers let you do this.
Let's say that you have a producer method that makes a "yellow" SomeObjDepA and another one that makes a "red" SomeObjDepA. To do this in CDI, you'll need qualifier annotations that express the "red" and "yellow" bits. Then apply them at the site of production. For example:
#ApplicationScoped // producer methods need to be "housed" in a bean
public class Host {
#Produces
#Red // you define this annotation following the spec's rules for qualifier annotations
#ApplicationScoped // ...or whatever scope is called for
public SomeDepA produceRedDepA() {
return new SomeDepA();
}
#Produces
#Yellow // you define this annotation following the spec's rules for qualifier annotations
#ApplicationScoped // ...or whatever scope is called for
public SomeDepA produceYellowDepA() {
return new SomeDepA();
}
}
Here we have two producer methods that will be called by the container appropriately and will "satisfy" relevant injection points elsewhere. For example, in SomeObject, you might have:
#Inject
#Red
private SomeDepA red;
#Inject
#Yellow
private SomeDepA yellow;

Is it possible to make Optional<T> and #Lazy work together in Spring?

I have to make me #Component #Lazy as it is used rarely and creates circular dependency problem
I have to make it Optional<T> because feature it represents can be disabled on startup (#ConditionalOnProperty) so it might not be available at runtime
Problem:
When I use Optional<T> as injection point, bean is initialized eagerly.
So the questions:
Is it possible to make it work like that?
Can I replace Optional<T> with Provider<T>? will it simply return null if feature is disabled or it will throw exception?
Can it be replaced with ObjectProvider<T>?
I would like to stick to #Resource or #Inject annotation so #Autowired(required=false) will be last resort for me.
There is no code to share here actually (as it would be class and field declarations as those are relevant onl IMHO)
Since you do not belive me the code is worthless here, let me share :)
#Comonent
#Lazy
public class MyType{
}
injection point
#Lazy
#Autowired
private Optional<MyType> myType;
usage
MyType instance=myType.getOrThrow(()->throw something)
Iv tested Optional and debugger hits MyType upon application startup. It is skipped when I use plain field, provider or object provider.
In situations like this I do not wire the Component directly, but lazily. There are different options:
Go through the ApplicationContext and retrieve MyType when you need it. You would only retrieve it, when you know it is enabled:
#Autowire
private ApplicationContext context;
...
MyType instance = context.getBean(MyType.class);
Provider or Factory approach, where you have an autowired service which provides you an instance of MyType. This service is also only called when the feature is enabled.
#Autowire
private MyTypeFactory factory;
...
MyType instance = factory.getMyType();
Using the Provider would require you to define a bean in your configuration, so it might be easier to just have a POJO service on which you can slap #Service, that does the same.
Let me present an alternative Point of View. I think that using Optional dependency for this is not justified.
The class that has an Autowired MyType probably counts on this dependency (notwithstanding the fact that usage of Optional for data fields if a kind of bad practice).
The reason for Laziness of the component also seems to be more "hack" than intention (circular dependency is never a good thing).
So, if we'll pretend that this class makes something "Optionally available", one way is to provide an additional no-op implementation for this MyType problematic bean:
interface MyType {
void doSomeHeavyStuff();
}
public class MyTypeRegularImpl() implements MyType {
public void doSomeHeavyStuff() {
....work..work..work..
}
}
public class NoOpMyType implements MyType {
public void doSomeHeavyStuff() {
// do nothing here
}
}
Now the trick is to provide two mutually exclusive conditions and make sure that only one bean out of these two loads (otherwise it will produce an ambiguity in beans and probably fail during the application startup).
So the class that uses MyType won't need Optional at all.
Now regarding the Laziness.
In general, Lazy beans only get ini
Lazy Bean can still be used since the bean will be initialized during the first call in a class that has that lazy dependency.
For no-op beans it won't matter at all.

How to setup a non-CDI bean from a 3rd party for #Inject into CDI bean

While I've found examples in CDI where you setup #Produces (kinda factory like) or using the CDI javax.enterprise.inject.spi.Unmanaged concepts, they all seem to presume that CDI will be the one creating the instance of the class on its own terms and lifecycle (which makes sense).
However, there are situations where CDI simply cannot create the instance.
Such as a 3rd party library (that isn't using CDI itself) which is creating the object internally and giving it to you.
Now, how can I take these already instantiated objects (which incidentally are final objects with no default constructor), and make them available for my CDI managed beans to then use?
Here's a simplified example.
public class Foo
{
#Inject
private ByteBuffer buf;
public void go()
{
// do something, with buffer
}
}
public void process() {
ByteBuffer buf = ByteBuffer.allocate(500);
// TODO: how to add "buf" to current context?
Foo foo = CDI.current().select(Foo.class,AnyLiteral.INSTANCE).get();
foo.go();
}
Now, I realize that for this specific example, I could eaily just pass in the ByteBuffer, or setup a #Produces for ByteBuffer, or even have Foo make the ByteBuffer itself. (all of which would be easier). I chose ByteBuffer, because it exhibits the same problems I'm facing with the 3rd party library
The instances are valid beans
I have no control over its source
Instances are created by the library
Those instances are final and cannot be wrapped, overridden, or proxied
The use case also has situations where there are nested CDI references that could also use access to this #Inject ByteBuffer buf;.
Ideally it would be keen to have this be a pure CDI api technique, and not something that is weld or implementation specific.
I've devled into custom Scope creation as well, thinking that might be a solution for this, having a sort of #BufferScope that identifies the start() and end() of this instance. But none of the examples and documentation make this very clear with regards to objects that CDI just cannot call newInstance() or produce() on. The object instantiation is out of my hands, but the ability to present it to a CDI Scope is possible, along with even managing the ultimate death / destruction of that instance.
Proxying is not the same as wrapping. A customary workaround is to create a ByteBufferHolder (insert your class here) that adapts the custom builder flow into a bean that understands that it's inside the DI context.
I'm not sure I agree with the original assertion that CDI assumes it is constructing the instances. For example, I use the following in a JSF application to inject the current FacesContext instance....
import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Produces;
import javax.faces.context.FacesContext;
public class FacesContextProducer {
#Produces #RequestScoped FacesContext getFacesContext() {
return FacesContext.getCurrentInstance();
}
}
At nowhere do I create the FacesContext instance. All that is required is that what has been created by the external framework is accessible.
So, if there is an external source from which you are getting instances, as long as you can get the correct one, the #Produces approach should still work?
There is some fundamental misunderstanding here. CDI is not required to construct the bean instances it can serve through producer methods. A Dependent scope will work just fine if the class is not proxyable. You can also make a wrapper class for the object, and put said class instances in whichever scope you need.
You use a producer method, which can be as simple as something like this:
#Produces
#ApplicationScoped
private Foo produceFoo() {
final Foo instance = // acquire one of those instances you're talking about
return instance;
}
If for whatever reason that doesn't work for you, you can alternatively write a portable extension and programmatically add a Bean that does what you want. So something like this in CDI 2.0+ (untested):
private void afterBeanDiscovery(#Observes final AfterBeanDiscovery event) {
final Foo instance = // acquire one of these final instances you're talking about
event.addBean()
.scope(ApplicationScoped.class)
.qualifiers(whateverYouNeed)
.addTransitiveTypeClosure(instance.getClass())
.createWith(cc -> instance) // you may also need .destroyWith()
;
}
Once you have this "producing side" set up, then in any CDI bean anywhere you can do:
#Inject
private Foo foo;

Java: creating a OCP based factory through Spring?

I have the following code:
public IFoo getFoo(Type type) // Type is an enum containing A, B etc.
{
switch(type)
{
case A: return new Foo1(); // implements IFoo
case B: return new Foo2(); // implements IFoo
etc.
}
}
This obviously violates OCP, so I need to refactor; plus I now need to return prototype beans which are managed by a Spring container. To achieve this, I can think of the following options:
1) make this class AppContextAware; create a Map<Type, String> where String is the bean id; define these beans as prototype in Spring Config and define this Map too in Spring config and get it injected in this class, then get the bean id from this map for a given enum and use it to get a bean from AppContext,
2) similar approach, but for the value in Map, use a TargetSource which has an abstract method which I call in getTarget() and I wire the defined prototype beans using lookup-method as this abstract method per TargetSource definition,
3) similar approach, but I use a FactoryBean instead of TargetSource.
In #1 my class depends on AppContext, in other approaches it doesn't. So I'm leaning towards #2 or #3, but which one to pick? Or is there any other, better approach that I haven't thought of?
I ended up using #1 anyway, as it's the simplest, and creates lesser number of beans.
Take a look at The FactoryBean, migth be the thing you are looking for. Take a look at here for an example.
hth

How can I inject an implementation of EJB 3 if I only know which one to use until runtime based on a condition?

Is there a way to decide what EJB implementation to use at runtime when you have more than one implementation? I can't use annotations or deployment descriptor because the logic is not known until runtime.
Let's say that I have the following EJBs implementations:
MyEJBFoo MyEJBBar, both implement MyEJB business interface. How can I still do dependency injection of that EJB if the implementation to use is known until runtime with let's say a flag called DEV_MODE = TRUE/FALSE stored in a resource bundle and if it is true it must use MyEJBFoo and if it is false then MyEJBBar.
I was thinking factory pattern but I'm not sure if it is the best way to do it.
Use a delegating MyEJB:
public class MyEJBDelegatingImpl implements MyEJB {
// Inject: can't remember exact annotation
private MyEJB myEJBFoo;
// Inject: can't remember exact annotation
private MyEJB myEJBBar;
private getDelegate() {
if (condition for myEJBFoo) {
return myEJBFoo;
} else {
return myEJBBar;
}
}
...
//Now implement MyEJB delegating to getDelegate()
}
Only caveat is that both instances (myEJBFoo and myEJBBar) have to be instantiable no matter what the environment conditions are, because you are injecting both unconditionally in the delegating MyEJB.
Just be aware of the resolving the injection points accordingly, when using one interface for two implementations (described here).
Furthermore, if you have the possibility to use CDI, check out the producer methods, as they make exactly such things possible.

Categories

Resources