Browse Source

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

Issue: SPR-11923
pull/573/head
Juergen Hoeller 11 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; @@ -23,10 +23,13 @@ import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Query;
import javax.persistence.TransactionRequiredException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@ -61,6 +64,23 @@ public abstract class SharedEntityManagerCreator { @@ -61,6 +64,23 @@ public abstract class SharedEntityManagerCreator {
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.
@ -246,6 +266,13 @@ public abstract class SharedEntityManagerCreator { @@ -246,6 +266,13 @@ public abstract class SharedEntityManagerCreator {
}
// 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.
boolean isNewEm = false;
@ -337,8 +364,7 @@ public abstract class SharedEntityManagerCreator { @@ -337,8 +364,7 @@ public abstract class SharedEntityManagerCreator {
throw ex.getTargetException();
}
finally {
if (method.getName().equals("getResultList") || method.getName().equals("getSingleResult") ||
method.getName().equals("executeUpdate")) {
if (queryTerminationMethods.contains(method.getName())) {
// Actual execution of the query: close the EntityManager right
// afterwards, since that was the only reason we kept it open.
EntityManagerFactoryUtils.closeEntityManager(this.em);

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

@ -1,5 +1,5 @@ @@ -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");
* you may not use this file except in compliance with the License.
@ -16,7 +16,9 @@ @@ -16,7 +16,9 @@
package org.springframework.orm.jpa;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.TransactionRequiredException;
import org.junit.Test;
@ -40,4 +42,46 @@ public class SharedEntityManagerCreatorTests { @@ -40,4 +42,46 @@ public class SharedEntityManagerCreatorTests {
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