Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
package demo.util;
import javassist.util.proxy.MethodFilter;
import javassist.util.proxy.MethodHandler;
import javassist.util.proxy.ProxyFactory;
import javassist.util.proxy.ProxyObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
* todo
public class JPAUtil {
private static Logger logger = LoggerFactory.getLogger(JPAUtil.class);
static EntityManagerFactory emf;
public static void init(String pm) {
Thread.currentThread().setContextClassLoader(Persistence.class.getClassLoader()); // scala REPL hack
emf = Persistence.createEntityManagerFactory(pm);
private static ThreadLocal<EntityManager> entityManagerThreadLocal = new ThreadLocal<EntityManager>();
private static ThreadLocal<Boolean> rollbackFlag = new ThreadLocal<Boolean>();
* Returns the <code>EntityManager</code> for this thread
* @return
public static EntityManager getEntityManager() {
if (emf == null)
throw new RuntimeException("JPAUtil not initialised, call init method first");
EntityManager entityManager = entityManagerThreadLocal.get();
if (entityManager == null) {
entityManager = emf.createEntityManager();
return entityManager;
* Creates an JPA transactional proxy with following semantics:
* <ul>
* <li>Shares an <code>EntityManager</code> </code> per thread</li>
* <li>Opens and closes the entityManager for each method call </li>
* <li>Transaction follow REQUIRED pattern (will join an existing transaction)</li>
* <li>Rollsback on any exception</li>
* </ul>
* This implementation does not inject the <code>EntityManager</code> into the target object
* @param clazz
* @param <T> The class for which to create a proxy (using Javassist)
* @return
public static <T> T getTransactionalProxy(Class<? extends T> clazz) {
ProxyFactory f = new ProxyFactory();
f.setFilter(new MethodFilter() {
public boolean isHandled(Method m) {
return Modifier.isPublic(m.getModifiers());
Class c = f.createClass();
MethodHandler mi = new MethodHandler() {
public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable {
final EntityManager entityManager = getEntityManager();
try {
final EntityTransaction transaction = entityManager.getTransaction();
boolean iOwnTransaction = !transaction.isActive();
if (iOwnTransaction) {
rollbackFlag.set(false); //this is a new call
Object returnValue = null;
try {
returnValue = proceed.invoke(self, args);
if (iOwnTransaction) {
if (rollbackFlag.get()) {"Rolling back transaction, as flag has been set");
} else
} catch (InvocationTargetException e) {
if (iOwnTransaction) {"Rolled back transaction due to exception", e);
} else {"Setting rollback-only flag due to exception", e);
throw e;
return returnValue;
} finally {
if (entityManager.isOpen()) {
final T instance;
try {
instance = (T) c.newInstance();
((ProxyObject) instance).setHandler(mi);
return instance;
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.