Browse Source

SharedEntityManagerCreator immediately throws TransactionRequiredException on persist, merge, remove etc (as required by JPA spec)

Issue: SPR-11923
pull/573/head
Juergen Hoeller 12 years ago
parent
commit
045d7357d5
  1. 30
      spring-orm/src/main/java/org/springframework/orm/jpa/SharedEntityManagerCreator.java
  2. 46
      spring-orm/src/test/java/org/springframework/orm/jpa/SharedEntityManagerCreatorTests.java

30
spring-orm/src/main/java/org/springframework/orm/jpa/SharedEntityManagerCreator.java

@ -23,10 +23,13 @@ import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Proxy; import java.lang.reflect.Proxy;
import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory; import javax.persistence.EntityManagerFactory;
import javax.persistence.Query; import javax.persistence.Query;
import javax.persistence.TransactionRequiredException;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@ -61,6 +64,23 @@ public abstract class SharedEntityManagerCreator {
private static final Class<?>[] NO_ENTITY_MANAGER_INTERFACES = new Class<?>[0]; private static final Class<?>[] NO_ENTITY_MANAGER_INTERFACES = new Class<?>[0];
private static final Set<String> transactionRequiringMethods = new HashSet<String>(6);
private static final Set<String> queryTerminationMethods = new HashSet<String>(3);
static {
transactionRequiringMethods.add("joinTransaction");
transactionRequiringMethods.add("flush");
transactionRequiringMethods.add("persist");
transactionRequiringMethods.add("merge");
transactionRequiringMethods.add("remove");
transactionRequiringMethods.add("refresh");
queryTerminationMethods.add("getResultList");
queryTerminationMethods.add("getSingleResult");
queryTerminationMethods.add("executeUpdate");
}
/** /**
* Create a transactional EntityManager proxy for the given EntityManagerFactory. * Create a transactional EntityManager proxy for the given EntityManagerFactory.
@ -246,6 +266,13 @@ public abstract class SharedEntityManagerCreator {
} }
// Still perform unwrap call on target EntityManager. // Still perform unwrap call on target EntityManager.
} }
else if (transactionRequiringMethods.contains(method.getName())) {
// We need a transactional target now, according to the JPA spec.
// Otherwise, the operation would get accepted but remain unflushed...
if (target == null) {
throw new TransactionRequiredException("No transactional EntityManager available");
}
}
// Regular EntityManager operations. // Regular EntityManager operations.
boolean isNewEm = false; boolean isNewEm = false;
@ -337,8 +364,7 @@ public abstract class SharedEntityManagerCreator {
throw ex.getTargetException(); throw ex.getTargetException();
} }
finally { finally {
if (method.getName().equals("getResultList") || method.getName().equals("getSingleResult") || if (queryTerminationMethods.contains(method.getName())) {
method.getName().equals("executeUpdate")) {
// Actual execution of the query: close the EntityManager right // Actual execution of the query: close the EntityManager right
// afterwards, since that was the only reason we kept it open. // afterwards, since that was the only reason we kept it open.
EntityManagerFactoryUtils.closeEntityManager(this.em); EntityManagerFactoryUtils.closeEntityManager(this.em);

46
spring-orm/src/test/java/org/springframework/orm/jpa/SharedEntityManagerCreatorTests.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2013 the original author or authors. * Copyright 2002-2014 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,7 +16,9 @@
package org.springframework.orm.jpa; package org.springframework.orm.jpa;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory; import javax.persistence.EntityManagerFactory;
import javax.persistence.TransactionRequiredException;
import org.junit.Test; import org.junit.Test;
@ -40,4 +42,46 @@ public class SharedEntityManagerCreatorTests {
is(notNullValue())); is(notNullValue()));
} }
@Test(expected = TransactionRequiredException.class)
public void transactionRequiredExceptionOnJoinTransaction() {
EntityManagerFactory emf = mock(EntityManagerFactory.class);
EntityManager em = SharedEntityManagerCreator.createSharedEntityManager(emf);
em.joinTransaction();
}
@Test(expected = TransactionRequiredException.class)
public void transactionRequiredExceptionOnFlush() {
EntityManagerFactory emf = mock(EntityManagerFactory.class);
EntityManager em = SharedEntityManagerCreator.createSharedEntityManager(emf);
em.flush();
}
@Test(expected = TransactionRequiredException.class)
public void transactionRequiredExceptionOnPersist() {
EntityManagerFactory emf = mock(EntityManagerFactory.class);
EntityManager em = SharedEntityManagerCreator.createSharedEntityManager(emf);
em.persist(new Object());
}
@Test(expected = TransactionRequiredException.class)
public void transactionRequiredExceptionOnMerge() {
EntityManagerFactory emf = mock(EntityManagerFactory.class);
EntityManager em = SharedEntityManagerCreator.createSharedEntityManager(emf);
em.merge(new Object());
}
@Test(expected = TransactionRequiredException.class)
public void transactionRequiredExceptionOnRemove() {
EntityManagerFactory emf = mock(EntityManagerFactory.class);
EntityManager em = SharedEntityManagerCreator.createSharedEntityManager(emf);
em.remove(new Object());
}
@Test(expected = TransactionRequiredException.class)
public void transactionRequiredExceptionOnRefresh() {
EntityManagerFactory emf = mock(EntityManagerFactory.class);
EntityManager em = SharedEntityManagerCreator.createSharedEntityManager(emf);
em.refresh(new Object());
}
} }

Loading…
Cancel
Save