I am using EJB3 in my application and I want to know can I inject
beans dynamically at runtime based on some parameter ?
Because I have a @Local
interface which extends several beans which works in different manner. So at run time I want to load each bean depend on the logic. So far I used usual JNDI lookup
But I would like to do it with @Inject
. Is there a way that I can inject the bean dynamically?
Here is my existing lookup
code. I pass the bean name as jndi
here and build the instance dynamically.
IService bean = (IService) initialContext.lookup(jndi+"Bean/local");
bean.initializeTimer(firstDate, period, request);
I have three beans for the moment.
first bean is SingleServiceBean
@Stateless
public class SingleServiceBean implements IService{
@Override
public void doSomething (){
log.debug("inside do something");
}
private final Log log = LogFactory.getLog(SingleServiceBean.class.getName());
}
Second bean is PeriodicService
@Stateless
public class PeriodicServiceBean implements IService{
@Override
public void doSomething (){
log.debug("inside do something");
}
private final Log log = LogFactory.getLog(PeriodicServiceBean.class.getName());
}
Third bean
@Stateless
public class AsyncServiceBean implements IService{
@Override
public void doSomething (){
log.debug("inside do something");
}
private final Log log = LogFactory.getLog(AsyncServiceBean.class.getName());
}
Qualifier :
@Qualifier
@Target({ TYPE, METHOD, PARAMETER, FIELD })
@Retention(RUNTIME)
@Documented
public @interface Services {
String type();
}
AnnotationLiteral
public class ServiceQualifier extends AnnotationLiteral<Services> implements Services{
private static final long serialVersionUID = 6471734834552932687L;
private String type;
public String TypeQualifier(String t) {
this.type = t;
return type;
}
public String type() {
return type;
}
}
And new bean class like below
@Services(type = "SingleService" )
@Stateless
public class SingleServiceBean implements IService{
.....
}
then I add the below lines in my bean caller class
@Inject
private Instance<IService> iServiceInstance;
public void someMethod() {
// this line gives me error by red underline in .select(...)
IService service = iServiceInstance.select(new ServiceQualifier().TypeQualifier("SingleService")).get();
}
Error I get in eclipse : "The method select(Annotation...) in the type Instance is not applicable for the arguments (String)"
Assuming you're using local interfaces, you would need to use a qualifier in CDI (rather than JNDI location). On your impl, do something like this:
@Local
@Stateless
@MyQualifier("someValue")
public class MyServiceOne implements IService {
...
}
Where MyQualifier
could have any value - even the JNDI name. Then when you want to resolve it, do this:
@Inject @Any
private Instance<IService> iServiceInstance;
...
IService service = iServiceInstance.select(new MyQualifierLiteral("someValue")).get();
MyQualifierLiteral
here is an AnnotationLiteral
that implements MyQualifier
. This is what it should look like:
import javax.enterprise.util.AnnotationLiteral;
public class MyQualifierLiteral extends AnnotationLiteral<MyQualifier> implements MyQualifier {
private final String value;
public MyQualifierLiteral(final String value) {
this.value = value;
}
@Override
public String value() {
return this.value;
}
}