Question

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

UPDATE

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

2nd Update

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

Was it helpful?

Solution

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

}

OTHER TIPS

Are firstdate, period and request runtime args? If so, you can only inject some kind of factory that creates the bean based on those properties.

If those values are fix at deployment or at least configurable, you can go with a Producer.

@Produces
public IService getTimer() {
  IService bean = (IService) initialContext.lookup(jndi+"Bean/local"); 
  bean.initializeTimer(firstDate, period, request);
  return bean;
}

You will need to find a way to supply the configuration values. Check the Qualifier concept or use System.set/get properties to transport the values.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top