Daniel Nuss
Daniel Nuss

Reputation: 361

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?

Upvotes: 3

Views: 7210

Answers (2)

Daniel Nuss
Daniel Nuss

Reputation: 361

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

Upvotes: 0

LightGuard
LightGuard

Reputation: 5378

You have to create a producer for an EntityManager. However, I wouldn't recommend doing it inside of an extension, it's not portable (it may work on all implementations, but this would be one of those grey areas). Entities also need to be produced instead of letting the CDI container handle it. If you need to do something with the entities at the start of the application I recommend using @Startup from the EJB spec.

Upvotes: 2

Related Questions