The target

I am using Weld in a plain Java application (alias Java SE). I would like to inject an entity manager and use a @Transactional annotation to mark a method as transactional. A transaction should be
started before the method is executed and commited after the method was called. In addition exceptions should cause a rollback of the transaction.

@ApplicationScoped  
public class PlayerServiceBean {

	@Inject
	private EntityManager em;

	@Transactional
	public void createPlayer(Player player) {
		em.persist(player);
	}
}

The wrong way

I found various discussions but as at the time of writing JBoss Weld is still young, there seems to be no various ideas floating around but no best way.

I found one proposal by the JBoss people. This approach makes use of an extension to initialize the EntityManagerFactory and adds an interceptor which handles the transaction. This approach suffers of a conceptional problem. Have a look at the interceptor.

	@Transactional @Interceptor
	public class EntityTransactionInterceptor {

		private @Inject @Any EntityManager em;

		@AroundInvoke
		public Object aroundInvoke(InvocationContext ic) throws Exception {
			boolean act = !em.getTransaction().isActive();
			if (act) em.getTransaction().begin();
			try {
				Object result = ic.proceed();
				if (act) em.getTransaction().commit();
				return result;
			}
			catch (Exception e) {
				if (act) em.getTransaction().rollback();
				throw e;
			} 
		}
	}

The entity manager is injected as application scoped bean. It cannot be closed by the interceptor which is required in case of an exception. In addition every time we call the method the same entity manager is used and the persistence context will grow. As long as the bean is not removed, the entity manager will not be closed. In case of @ApplicationScoped it will never be closed. We cannot use this bean with two threads as well.

The right way

We need a different entity manager injected per thread and if the interceptor rolls back a transaction, it needs to be able to replace the entity manager in a bean. Either we need to create a custom scope which causes injection every time a method is called on the bean or we need to fake an entity manager which delegates to the current managed entity manager of the interceptor. I am not sure if the first approach works and I am not a weld expert either. Therefor I used the latter approach.

Steps to go

Create a transaction annotation

An annotation is pretty simple to write. Here is the complete source code. The @InterceptorBinding tells Weld that this annotation can be used with an interceptor.

package de.laliluna.transactions;

import javax.interceptor.InterceptorBinding;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD, ElementType.TYPE})
@InterceptorBinding
@Retention(RetentionPolicy.RUNTIME)
public @interface Transactional {
}

Create a entity manager store

We define an interface in case we want to change our implementation later on.

package de.laliluna.transactions;

import javax.persistence.EntityManager;

/**
 * @author Sebastian Hennebrueder
 */
public interface EntityManagerStore {
	/**
	 * Looks for the current entity manager and returns it. If no entity manager
	 * was found, this method logs a warn message and returns null. This will cause a NullPointerException in most
	 * cases and will cause a stack trace starting from your service method.
	 *
	 * @return the currently used entity manager or {@code null} if none was found
	 */
	EntityManager get();

	/**
	 * Creates an entity manager and stores it in a stack. The use of a stack allows to implement
	 * transaction with a 'requires new' behaviour.
	 *
	 * @return the created entity manager
	 */
	EntityManager createAndRegister();

	/**
	 * Removes an entity manager from the thread local stack. It needs to be created using the
	 * {@link #createAndRegister()} method.
	 *
	 * @param entityManager - the entity manager to remove
	 * @throws IllegalStateException in case the entity manager was not found on the stack
	 */
	void unregister(EntityManager entityManager);
}

And here is the implementation. The entity manager store stores the entity manager in a thread local. In addition it is responsible to initialize the EntityManagerFactory.
This is a simple implementation. If we want to support multiple EntityManagerFactories we might need to refactor this class.

package de.laliluna.transactions;

import org.jboss.weld.environment.se.events.ContainerInitialized;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import java.util.Stack;

/**
 * A store for entity managers. It is basically a ThreadLocal which stores the entity manager.
 * The {@link de.laliluna.transactions.TransactionInterceptor} is expected to register entity manager. The application code
 * can get the current entity manager either by injecting the store or the {@link EntityManagerDelegate}.
 *
 * @author Sebastian Hennebrueder
 */
@ApplicationScoped
public class EntityManagerStoreImpl implements EntityManagerStore {

	final Logger logger = LoggerFactory.getLogger(EntityManagerStoreImpl.class);

	private EntityManagerFactory emf;

	private ThreadLocal<Stack<EntityManager>> emStackThreadLocal = new ThreadLocal<Stack<EntityManager>>();

	public void init(@Observes ContainerInitialized containerInitialized) {
		emf = Persistence.createEntityManagerFactory("samplePU");
	}

	@Override
	public EntityManager get() {
		logger.debug("Getting the current entity manager");
		final Stack<EntityManager> entityManagerStack = emStackThreadLocal.get();
		if (entityManagerStack == null || entityManagerStack.isEmpty()) {
			/* if nothing is found, we return null to cause a NullPointer exception in the business code.
			This leeds to a nicer stack trace starting with client code.
			 */

			logger.warn("No entity manager was found. Did you forget to mark your method " +
					"as transactional?");

			return null;
		} else
			return entityManagerStack.peek();
	}

	/**
	 * Creates an entity manager and stores it in a stack. The use of a stack allows to implement
	 * transaction with a 'requires new' behaviour.
	 *
	 * @return the created entity manager
	 */
	@Override
	public EntityManager createAndRegister() {
		logger.debug("Creating and registering an entity manager");
		Stack<EntityManager> entityManagerStack = emStackThreadLocal.get();
		if (entityManagerStack == null) {
			entityManagerStack = new Stack<EntityManager>();
			emStackThreadLocal.set(entityManagerStack);
		}

		final EntityManager entityManager = emf.createEntityManager();
		entityManagerStack.push(entityManager);
		return entityManager;
	}

	/**
	 * Removes an entity manager from the thread local stack. It needs to be created using the
	 * {@link #createAndRegister()} method.
	 *
	 * @param entityManager - the entity manager to remove
	 * @throws IllegalStateException in case the entity manager was not found on the stack
	 */
	@Override
	public void unregister(EntityManager entityManager) {
		logger.debug("Unregistering an entity manager");
		final Stack<EntityManager> entityManagerStack = emStackThreadLocal.get();
		if (entityManagerStack == null || entityManagerStack.isEmpty())
			throw new IllegalStateException("Removing of entity manager failed. Your entity manager was not found.");

		if (entityManagerStack.peek() != entityManager)
			throw new IllegalStateException("Removing of entity manager failed. Your entity manager was not found.");
		entityManagerStack.pop();
	}
}
	

Create an interceptor

Now, we can create a transaction interceptor. It will start a transaction before a transactional method is called and commit it after the method was executed.
In addition it will register an entity manager in the EntityManagerStore and unregister it afterwards. Finally, it will roll back transactions in case of an exception.

The annotations @Interceptor and @Transactional tell Weld that every time it finds a @Transactional annotation it needs to call the interceptor.

package de.laliluna.transactions;

import org.hibernate.HibernateException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Inject;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;
import javax.persistence.EntityManager;

/**
 * A simple transaction interceptor which registers an entity mangager in a ThreadLocal and unregisters after the
 * method was called.
 * It does not support any kind of context propagation. If a transactional method calls another's bean transactional
 * method a new entity manager is created and added to the stack.
 *
 * @author Sebastian Hennebrueder
 */
@Interceptor
@Transactional
public class TransactionInterceptor {

	@Inject
	private EntityManagerStoreImpl entityManagerStore;

	private Logger logger = LoggerFactory.getLogger(TransactionInterceptor.class);

	@AroundInvoke
	public Object runInTransaction(InvocationContext invocationContext) throws Exception {

		EntityManager em = entityManagerStore.createAndRegister();

		Object result = null;
		try {
			em.getTransaction().begin();

			result = invocationContext.proceed();

			em.getTransaction().commit();

		} catch (Exception e) {
			try {
				if (em.getTransaction().isActive()) {
					em.getTransaction().rollback();
					logger.debug("Rolled back transaction");
				}
			} catch (HibernateException e1) {
				logger.warn("Rollback of transaction failed -> " + e1);
			}
			throw e;
		} finally {
			if (em != null) {
				entityManagerStore.unregister(em);
				em.close();
			}
		}


		return result;
	}
}
	

Don’t forget to add your interceptor to the META-INF/beans.xml

<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">
	<interceptors>
		<class>de.laliluna.transactions.TransactionInterceptor</class>
	</interceptors>
</beans>
	

This implementation will cause a separate entity manager for every transactional method. If you are aware of EJB3 or Spring transactions, then you will probably know the transaction type requires_new.
It is the same approach. If you want to achieve context propagation as in a EJB3, we need to improve our implementation. I leave the task to you but will outline the required steps.

Create a fake entity manager

The fake entity manager is not the real instance of the entity manager but it is a delegate. It will fetch the current entity manager from the EntityManagerStore and will delegate to this entity manager.

Don’t forget that your IDE can generate delegate methods. Don’t write the code!

package de.laliluna.transactions;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.persistence.*;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.metamodel.Metamodel;
import java.util.Map;

/**
 * @author Sebastian Hennebrueder
 */
@ApplicationScoped
public class EntityManagerDelegate implements EntityManager{

	@Inject
	private EntityManagerStore entityManagerStore;

	public void persist(Object entity) {
		entityManagerStore.get().persist(entity);
	}

	public <T> T merge(T entity) {
		return entityManagerStore.get().merge(entity);
	}

	public void remove(Object entity) {
		entityManagerStore.get().remove(entity);
	}

	public <T> T find(Class<T> entityClass, Object primaryKey) {
		return entityManagerStore.get().find(entityClass, primaryKey);
	}

	public <T> T find(Class<T> entityClass, Object primaryKey, Map<String, Object> properties) {
		return entityManagerStore.get().find(entityClass, primaryKey, properties);
	}

	public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode) {
		return entityManagerStore.get().find(entityClass, primaryKey, lockMode);
	}

	public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode, Map<String, Object> properties) {
		return entityManagerStore.get().find(entityClass, primaryKey, lockMode, properties);
	}

	public <T> T getReference(Class<T> entityClass, Object primaryKey) {
		return entityManagerStore.get().getReference(entityClass, primaryKey);
	}

	public void flush() {
		entityManagerStore.get().flush();
	}

	public void setFlushMode(FlushModeType flushMode) {
		entityManagerStore.get().setFlushMode(flushMode);
	}

	public FlushModeType getFlushMode() {
		return entityManagerStore.get().getFlushMode();
	}

	public void lock(Object entity, LockModeType lockMode) {
		entityManagerStore.get().lock(entity, lockMode);
	}

	public void lock(Object entity, LockModeType lockMode, Map<String, Object> properties) {
		entityManagerStore.get().lock(entity, lockMode, properties);
	}

	public void refresh(Object entity) {
		entityManagerStore.get().refresh(entity);
	}

	public void refresh(Object entity, Map<String, Object> properties) {
		entityManagerStore.get().refresh(entity, properties);
	}

	public void refresh(Object entity, LockModeType lockMode) {
		entityManagerStore.get().refresh(entity, lockMode);
	}

	public void refresh(Object entity, LockModeType lockMode, Map<String, Object> properties) {
		entityManagerStore.get().refresh(entity, lockMode, properties);
	}

	public void clear() {
		entityManagerStore.get().clear();
	}

	public void detach(Object entity) {
		entityManagerStore.get().detach(entity);
	}

	public boolean contains(Object entity) {
		return entityManagerStore.get().contains(entity);
	}

	public LockModeType getLockMode(Object entity) {
		return entityManagerStore.get().getLockMode(entity);
	}

	public void setProperty(String propertyName, Object value) {
		entityManagerStore.get().setProperty(propertyName, value);
	}

	public Map<String, Object> getProperties() {
		return entityManagerStore.get().getProperties();
	}

	public Query createQuery(String qlString) {
		return entityManagerStore.get().createQuery(qlString);
	}

	public <T> TypedQuery<T> createQuery(CriteriaQuery<T> criteriaQuery) {
		return entityManagerStore.get().createQuery(criteriaQuery);
	}

	public <T> TypedQuery<T> createQuery(String qlString, Class<T> resultClass) {
		return entityManagerStore.get().createQuery(qlString, resultClass);
	}

	public Query createNamedQuery(String name) {
		return entityManagerStore.get().createNamedQuery(name);
	}

	public <T> TypedQuery<T> createNamedQuery(String name, Class<T> resultClass) {
		return entityManagerStore.get().createNamedQuery(name, resultClass);
	}

	public Query createNativeQuery(String sqlString) {
		return entityManagerStore.get().createNativeQuery(sqlString);
	}

	public Query createNativeQuery(String sqlString, Class resultClass) {
		return entityManagerStore.get().createNativeQuery(sqlString, resultClass);
	}

	public Query createNativeQuery(String sqlString, String resultSetMapping) {
		return entityManagerStore.get().createNativeQuery(sqlString, resultSetMapping);
	}

	public void joinTransaction() {
		entityManagerStore.get().joinTransaction();
	}

	public <T> T unwrap(Class<T> cls) {
		return entityManagerStore.get().unwrap(cls);
	}

	public Object getDelegate() {
		return entityManagerStore.get().getDelegate();
	}

	public void close() {
		entityManagerStore.get().close();
	}

	public boolean isOpen() {
		return entityManagerStore.get().isOpen();
	}

	public EntityTransaction getTransaction() {
		return entityManagerStore.get().getTransaction();
	}

	public EntityManagerFactory getEntityManagerFactory() {
		return entityManagerStore.get().getEntityManagerFactory();
	}

	public CriteriaBuilder getCriteriaBuilder() {
		return entityManagerStore.get().getCriteriaBuilder();
	}

	public Metamodel getMetamodel() {
		return entityManagerStore.get().getMetamodel();
	}
}
	

Using your implementation

Here is a simple service.

package de.laliluna.beans;

import de.laliluna.transactions.Transactional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Inject;
import javax.persistence.EntityManager;

public class PlayerServiceBean {

	@Inject
	private EntityManager em;

	@Transactional
	public void createPlayer(Player player) {
		em.persist(player);
	}
}
	
public static void main(String[] args) {		
	// start up the container
	WeldContainer weldContainer = new Weld().initialize();
	// fire an event to cause the entity manager factory initialize itself
	weldContainer.event().select(ContainerInitialized.class).fire(new ContainerInitialized());
    
	// get your bean
	PlayerServiceBean playerServiceBean = weldContainer.instance().select(PlayerServiceBean.class).get();
	
	playerServiceBean.createPlayer(new Player("Sean"));
}	

Final words

I hope you have enjoyed the article.

Best Regards / Viele Grüße

Sebastian Hennebrueder