Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic CDI Injection at runtime

This question comes will be referenced from my blog post I wrote a year ago.

Though I use custom CDI qualifier for my DAO, I wanted to know if there is an approach to inject DAO's dynamically.

The reason I ask is as follows. For now I have 3 CDI qualifiers, @HibernateDAO (for Hibernate Session injection type DAO), @JPADAO (for JPA specific DAO's) and @JDBCDAO (for purely JDBCDAO). This requires that I have to specify it on each concrete implementation and upon injection like so.

@Inject @JPADAO
private CustomerDAO customerDAO;

Is there a better approach that will allow me to add various flavours of DAO without having to change code, compile and deploy?

I want to introduce MongoDB in the next release of my project and I was thinking if I can move away from @MongoDBDAO and injection like,

@Inject @MongoDBDAO
private CustomerDAO customerDAO;

I know that CDI Injection can allow default and alternative injection. I want to have a possibility that other developers can use the override the default implementations with another subclass and be able to inject it without changing existing service code.

Something of this effect:

@Inject @DAO
private CustomerDAO customerDAO;

Where @DAO can be any DAO of any flavour (even from 3rd party) and somehow map @DAO to first find the alternative, if not found, used default implementation.

Thanks.

Oh! This solution must strictly work with the latest (as current time of writing) Java EE CDI specification. Technology used:

  • RedHat JBoss Wildfly 8.2.0 Final (Fully Java EE 7 compliant).
  • Java 8.
  • Java EE 7 API's.

I won't downvote a solution that uses Spring Framework as it can help other Spring developers.

like image 383
Buhake Sindi Avatar asked Feb 11 '23 09:02

Buhake Sindi


2 Answers

If you want to inject Daos generically at runtime, i would recommend this approach.

@Qualifier
@Retention(RUNTIME)
@Target({TYPE,METHOD,FIELD,PARAMETER})
public @interface DAO{

  String value();
}

//Dont worry, CDI allows this quite often than not ;)
public class DAOImpl extends AnnotationLiteral<DAO> implements DAO {

   private final String name;
   public DAOImpl(final String name) {
     this.name = name;
   }

   @Override
   public String value() {
     return name;
   }
}

Where it is required.

@ApplicationScoped; //Or Whatever
public class MyDAOConsumer {

   @Inject
   @Any
   private Instance<DAOService> daoServices;

   //Just as an example where you can get the dynamic configurations for selecting daos. 
   //Even from property files, or system property.
   @Inject
   private MyDynamicConfigurationService myDanamicConfigurationService;

   public void doSomethingAtRuntime() {
     final String daoToUse = myDanamicConfigurationService.getCurrentConfiguredDaoName();
     final DAO dao = new DAOImpl(daoToUse);

     //Careful here if the DaoService does not exist, you will get UnsatisfiedException
     final DAOService daoService = daoServices.select(dao).get();
     daoService.service();
   }
}

And bumped, you can configure which dao to use at runtime without a sweat. And without changing any tiny bit of code.

like image 161
maress Avatar answered Feb 13 '23 02:02

maress


I would forget about the custom annotations and use a producer method. In that method you could lookup the class you want to instantiate from an xml file or config file or whatever way you want to do it.

Take a look at Producer Methods in the Java EE tutorial.

like image 21
mamboking Avatar answered Feb 13 '23 04:02

mamboking