JPA and CDI using @Alternative producers

When using this approach we suppose that it's known at compile time the EntityManager that will be used in each method or class. If on the other hand you want to address this issue at packaging time, you can use the @Alternative annotation.

The @Alternative annotation lets you package multiple beans that match an injection point without ambiguity errors. In other words, you can apply the @Alternative annotation to two or more beans, then, based on your deployment, specify the bean you want to use in CDI's beans.xml configuration file.

For example, here we will declare two database producers, one for MySQL and one for Default database:

package com.sample;

import javax.enterprise.inject.Alternative;

import javax.enterprise.inject.Produces;
import javax.persistence.EntityManager;

import javax.persistence.PersistenceContext;

@Alternative
public class MySQLDatabaseProducer {

    @Produces
    @PersistenceContext(unitName = "primary")
    private EntityManager em;


}

 

package com.sample;

import javax.enterprise.inject.Alternative;
import javax.enterprise.inject.Produces;
import javax.persistence.EntityManager;

import javax.persistence.PersistenceContext;

@Alternative
public class DefaultDatabaseProducer {

    @Produces
    @PersistenceContext(unitName = "secondary")
    private EntityManager em;


}


Now, each time you inject an Entity Manager:

@Inject
private EntityManager em;


the choice of which EntityManager will be resolved by CDI's beans.xml file (placed into the WEB-INF folder of your Web application).

<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://java.sun.com/xml/ns/javaee 
        http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
    
<alternatives>
  <class>com.sample.MySQLDatabaseProducer</class>
</alternatives>       
</beans>

Specifying the default Entity Manager properties

One more trick you can do with CDI, is defining a method and marking it as producer, This way, it will be called each time an EntityManeger object is needed. For example, here we are injecting some properties into our EntityManager once it is created. This can be useful for example if you have multiple databases with the same schemas, but using a different dialect (ex. MySQL-Oracle) and we want to choose dynamically which dialect will be used:

    @PersistenceUnit(unitName = "primary")
    private EntityManagerFactory emf;

    @Produces
    @PersistenceContext(unitName = "primary")
    public void createEntityManager() {

     Map props = new HashMap();
     props.put("hibernate.show_sql","true");
     props.put("hibernate.dialect","org.hibernate.dialect.MySQLDialect");
     props.put("hibernate.show_sql","true");
     props.put("hibernate.format_sql","true");


     EntityManager emy = emf.createEntityManager(props);
    }

    
Finally, each resource Producer might have a corresponding resource Disposer which can be used to perform some clean up actions before removing the instance. For example, here's how you can dispose the EntityManager created by the createEntityManager method:

 public void dispose(@Disposes @Default EntityManager entityManager)
    {
        if(entityManager.isOpen())
        {
            entityManager.close();
        }
    }
0
0
0
s2sdefault