I am running a project using Hibernate and Weld CDI on tomcat 7. I have write a ServletContextListener to create the EntityManagerFactory and EntityManager during application startup.
public class PersistenceListener implements ServletContextListener {
private static EntityManagerFactory entityManagerFactory;
public void contextInitialized(ServletContextEvent sce){
ServletContext context = sce.getServletContext();
entityManagerFactory = Persistence.createEntityManagerFactory("hibernate-test");
}
public void contextDestroyed(ServletContextEvent sce) {
entityManagerFactory.close();
}
public static EntityManager createEntityManager() {
if (entityManagerFactory == null) {
throw new IllegalStateException("Context is not initialized yet.");
}
return entityManagerFactory.createEntityManager();
}
}
I can use my entityManager in my test class (it is an arquillian test class) simply by creating it through the following code
EntityManager em = PersistenceListener.createEntityManager();
em.getTransaction().begin();
em.createQuery("delete from Game").executeUpdate();
em.getTransaction().commit();
here is the complete code for my test class
@RunWith(Arquillian.class)
public class HibernateTestSample {
@Deployment
public static WebArchive createTestArchive()
{
MavenDependencyResolver resolver = DependencyResolvers.use(
MavenDependencyResolver.class).loadMetadataFromPom("pom.xml");
WebArchive webArchive= ShrinkWrap
.create(WebArchive.class, "ROOT.war")
.addClasses(CdiTestBean.class,HibernateListener.class,PersistenceListener.class)
.addAsLibraries(
resolver.artifact("org.jboss.weld.servlet:weld-servlet")
// .artifact("org.hibernate.javax.persistence:hibernate-jpa-2.0-api")
.artifact("org.apache.tomcat:tomcat-dbcp")
.artifact("org.hibernate:hibernate-entitymanager")
.artifact("org.hibernate:hibernate-validator")
.artifact("org.hibernate:hibernate-core")
.artifact("com.h2database:h2")
.artifact("mysql:mysql-connector-java")
.resolveAs(GenericArchive.class))
.addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml")
.addAsWebInfResource("test-persistence.xml", "classes/META-INF/persistence.xml")
.addAsWebInfResource("hibernate.cfg.xml", "classes/hibernate.cfg.xml")
// .addAsWebInfResource("context.xml", "classes/META-INF/context.xml")
.addAsManifestResource("context.xml", "context.xml")
.setWebXML("hibernate-web.xml");
System.out.println(webArchive.toString(true));
return webArchive;
}
@Test
public void myTest()
throws Exception {
EntityManager em = PersistenceListener.createEntityManager();
em.getTransaction().begin();
em.createQuery("delete from Game").executeUpdate();
em.getTransaction().commit();
...............
.......
...
}
}
but I want to inject my entityManager to my class. I read in an other post that I cannot use @PersistenceContext in my class, therefor I decided to use a producer to inject my entity manager. but it doesn't work for my, please tell me what am i doing wrong here (I am quite new in CDI )
here is my new ServletContextListener
public class PersistenceListener implements ServletContextListener {
private static EntityManagerFactory entityManagerFactory;
@Produces
private EntityManager entityManager;
public void contextInitialized(ServletContextEvent sce){
ServletContext context = sce.getServletContext();
entityManagerFactory = Persistence.createEntityManagerFactory("hibernate-test");
createEntityManager();
}
public void contextDestroyed(ServletContextEvent sce) {
entityManagerFactory.close();
}
public void createEntityManager() {
if (entityManagerFactory == null) {
throw new IllegalStateException("Context is not initialized yet.");
}
this.entityManager = entityManagerFactory.createEntityManager();
}
and I am injecting in my testclass
@Inject
private EntityManager em;
It is null
The instance created through the Servlet specification by implementing ServletContextListener is not the same instance as CDI will create later on to resolve your @Produces
field.
Further I recommend this informative blog post about the EntityManager: http://struberg.wordpress.com/2012/04/25/is-there-a-way-to-fix-the-jpa-entitymanager/
It might be slighly outdated though because if I recall correctly I have seen @TransactionScoped in the works over at deltaspike.
Lastly as you may have figured by now having a singleton EntityManager is not what you want but for the sake of completeness the miss in synergy between your ContextListener and CDI can be somewhat fixed by using CdiCtrl from Deltaspike and BeanProvider from Deltspike Core.
How to attach CDI ApplicationScope to to your current thread http://struberg.wordpress.com/2012/03/17/controlling-cdi-containers-in-se-and-ee/
And then you can pickup a bean that is annotated with @ApplicationScoped
and set it up. The pickup is done with MyBean myBean = BeanProvider.getContextualReference(MyBean.class, false);
http://deltaspike.apache.org/deltaspike/core.html
Hopefully CDI 1.1 will make this a little more fluent
Update: The talk on the Deltaspike list is to have 0.5 be a smaller release in about a month. Hopefully the new Servlet module will solve this nicely.
https://issues.apache.org/jira/browse/DELTASPIKE-376 https://issues.apache.org/jira/browse/DELTASPIKE-377
You need @Produces
on your createEntityManager
method, instead of the field.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With