Search code examples
hibernatejpajava-ee-6cdi

Use entity manager in CDI extension


I want to write a CDI extension which loads some entities from database (which are in fact groovy scripts that implement a certain interface) and provide them as beans, so that it is possible to get all implementations of this interface injected by CDI. I think of sth. like the following:

public class ExtensionClass implements Extension {
  @Inject 
  EntityManager em;

  public void afterBeanDiscovery(@Observes final AfterBeanDiscovery event, final BeanManager manager) {
    Entity entity = em.find();
    //do sth with entity...
  }
}

When i try to inject the entity manager this way, it is null (which does not surprise me that much, i did not expect @Inject to work inside a CDI extension class).

Is it possible to get access to the entity manager inside a CDI extension somehow (via BeanManager for example)? Or do i have to access the db in another way?


Solution

  • If anyone is interested how to get the entity manager inside a CDI extension, this is how i did it. First, as LightGuard said, you have to create a producer to make the entity manager available:

     @Produces
     @MyQualifier
     public javax.persistence.EntityManager create() {
       return entityManager;
     }
    

    In the cdi extension, you then can do the following:

     public class ScriptingExtension implements Extension {
       public void afterBeanDiscovery(@Observes final AfterBeanDiscovery event, final BeanManager manager) {
         final Set<Bean<?>> embeans = manager.getBeans(EntityManager.class);
         final Bean<?> bean = manager.resolve(embeans);
    
         final CreationalContext<?> creationalContext = manager.createCreationalContext(bean);
         final EntityManager em = (EntityManager) manager.getReference(bean, EntityManager.class, creationalContext);
         //do sth with entity manager... 
        }
      }
    

    Please notice that the entity manager in this case is only available at this point of the container CDI lifecycle and not earlier (like e.g. in ProcessAnnotatedType). In my case this was a problem, because i wanted to veto some of the beans, for which i had to intercept earlier. So i chose to use a direct JNDI lookup to the datasource to load the information relevant for me, sth. like this:

    final InitialContext ctx = new InitialContext();
    final DataSource dataSource = (DataSource) ctx.lookup("java:/jdbc/myDatasource");