Skip to content

Commit b9df984

Browse files
samebGuice Team
authored and
Guice Team
committed
accomodate manually initiated rollbacks. Fixes #1137 & fixes #1136.
PiperOrigin-RevId: 525746602
1 parent 7ed6624 commit b9df984

File tree

2 files changed

+98
-38
lines changed

2 files changed

+98
-38
lines changed

extensions/persist/src/com/google/inject/persist/jpa/JpaLocalTxnInterceptor.java

+21-13
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@
2525
import org.aopalliance.intercept.MethodInterceptor;
2626
import org.aopalliance.intercept.MethodInvocation;
2727

28-
/** @author Dhanji R. Prasanna ([email protected]) */
28+
/**
29+
* @author Dhanji R. Prasanna ([email protected])
30+
*/
2931
class JpaLocalTxnInterceptor implements MethodInterceptor {
3032

3133
// TODO(gak): Move these args to the cxtor & make these final.
@@ -64,12 +66,12 @@ public Object invoke(MethodInvocation methodInvocation) throws Throwable {
6466
result = methodInvocation.proceed();
6567

6668
} catch (Exception e) {
67-
//commit transaction only if rollback didnt occur
69+
// commit transaction only if rollback didnt occur
6870
if (rollbackIfNecessary(transactional, e, txn)) {
6971
txn.commit();
7072
}
7173

72-
//propagate whatever exception is thrown anyway
74+
// propagate whatever exception is thrown anyway
7375
throw e;
7476
} finally {
7577
// Close the em if necessary (guarded so this code doesn't run unless catch fired).
@@ -79,19 +81,25 @@ public Object invoke(MethodInvocation methodInvocation) throws Throwable {
7981
}
8082
}
8183

82-
//everything was normal so commit the txn (do not move into try block above as it
84+
// everything was normal so commit the txn (do not move into try block above as it
8385
// interferes with the advised method's throwing semantics)
8486
try {
85-
txn.commit();
87+
if (txn.isActive()) {
88+
if (txn.getRollbackOnly()) {
89+
txn.rollback();
90+
} else {
91+
txn.commit();
92+
}
93+
}
8694
} finally {
87-
//close the em if necessary
95+
// close the em if necessary
8896
if (null != didWeStartWork.get()) {
8997
didWeStartWork.remove();
9098
unitOfWork.end();
9199
}
92100
}
93101

94-
//or return result
102+
// or return result
95103
return result;
96104
}
97105

@@ -125,28 +133,28 @@ private boolean rollbackIfNecessary(
125133
Transactional transactional, Exception e, EntityTransaction txn) {
126134
boolean commit = true;
127135

128-
//check rollback clauses
136+
// check rollback clauses
129137
for (Class<? extends Exception> rollBackOn : transactional.rollbackOn()) {
130138

131-
//if one matched, try to perform a rollback
139+
// if one matched, try to perform a rollback
132140
if (rollBackOn.isInstance(e)) {
133141
commit = false;
134142

135-
//check ignore clauses (supercedes rollback clause)
143+
// check ignore clauses (supercedes rollback clause)
136144
for (Class<? extends Exception> exceptOn : transactional.ignore()) {
137-
//An exception to the rollback clause was found, DON'T rollback
145+
// An exception to the rollback clause was found, DON'T rollback
138146
// (i.e. commit and throw anyway)
139147
if (exceptOn.isInstance(e)) {
140148
commit = true;
141149
break;
142150
}
143151
}
144152

145-
//rollback only if nothing matched the ignore check
153+
// rollback only if nothing matched the ignore check
146154
if (!commit) {
147155
txn.rollback();
148156
}
149-
//otherwise continue to commit
157+
// otherwise continue to commit
150158

151159
break;
152160
}

extensions/persist/test/com/google/inject/persist/jpa/ManagedLocalTransactionsTest.java

+77-25
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package com.google.inject.persist.jpa;
1818

19+
import static org.junit.Assert.assertThrows;
20+
1921
import com.google.inject.Guice;
2022
import com.google.inject.Inject;
2123
import com.google.inject.Injector;
@@ -29,7 +31,9 @@
2931
import javax.persistence.NoResultException;
3032
import junit.framework.TestCase;
3133

32-
/** @author Dhanji R. Prasanna ([email protected]) */
34+
/**
35+
* @author Dhanji R. Prasanna ([email protected])
36+
*/
3337

3438
public class ManagedLocalTransactionsTest extends TestCase {
3539
private Injector injector;
@@ -41,7 +45,7 @@ public class ManagedLocalTransactionsTest extends TestCase {
4145
public void setUp() {
4246
injector = Guice.createInjector(new JpaPersistModule("testUnit"));
4347

44-
//startup persistence
48+
// startup persistence
4549
injector.getInstance(PersistService.class).start();
4650
}
4751

@@ -57,7 +61,7 @@ public void testSimpleTransaction() {
5761
EntityManager em = injector.getInstance(EntityManager.class);
5862
assertFalse("txn was not closed by transactional service", em.getTransaction().isActive());
5963

60-
//test that the data has been stored
64+
// test that the data has been stored
6165
Object result =
6266
em.createQuery("from JpaTestEntity where text = :text")
6367
.setParameter("text", UNIQUE_TEXT)
@@ -79,7 +83,7 @@ public void testSimpleTransactionWithMerge() {
7983
EntityManager em = injector.getInstance(EntityManager.class);
8084
assertFalse("txn was not closed by transactional service", em.getTransaction().isActive());
8185

82-
//test that the data has been stored
86+
// test that the data has been stored
8387
assertTrue("Em was closed after txn!", em.isOpen());
8488

8589
Object result =
@@ -100,7 +104,7 @@ public void testSimpleTransactionRollbackOnChecked() {
100104
try {
101105
injector.getInstance(TransactionalObject.class).runOperationInTxnThrowingChecked();
102106
} catch (IOException e) {
103-
//ignore
107+
// ignore
104108
injector.getInstance(UnitOfWork.class).end();
105109
}
106110

@@ -110,23 +114,21 @@ public void testSimpleTransactionRollbackOnChecked() {
110114
"Previous EM was not closed by transactional service (rollback didnt happen?)",
111115
em.getTransaction().isActive());
112116

113-
//test that the data has been stored
114-
try {
115-
Object result =
116-
em.createQuery("from JpaTestEntity where text = :text")
117-
.setParameter("text", TRANSIENT_UNIQUE_TEXT)
118-
.getSingleResult();
119-
injector.getInstance(UnitOfWork.class).end();
120-
fail("a result was returned! rollback sure didnt happen!!!");
121-
} catch (NoResultException e) {
122-
}
117+
// test that the data has been stored
118+
assertThrows(
119+
NoResultException.class,
120+
() ->
121+
em.createQuery("from JpaTestEntity where text = :text")
122+
.setParameter("text", TRANSIENT_UNIQUE_TEXT)
123+
.getSingleResult());
124+
injector.getInstance(UnitOfWork.class).end();
123125
}
124126

125127
public void testSimpleTransactionRollbackOnUnchecked() {
126128
try {
127129
injector.getInstance(TransactionalObject.class).runOperationInTxnThrowingUnchecked();
128130
} catch (RuntimeException re) {
129-
//ignore
131+
// ignore
130132
injector.getInstance(UnitOfWork.class).end();
131133
}
132134

@@ -135,15 +137,47 @@ public void testSimpleTransactionRollbackOnUnchecked() {
135137
"Session was not closed by transactional service (rollback didnt happen?)",
136138
em.getTransaction().isActive());
137139

138-
try {
139-
Object result =
140-
em.createQuery("from JpaTestEntity where text = :text")
141-
.setParameter("text", TRANSIENT_UNIQUE_TEXT)
142-
.getSingleResult();
143-
injector.getInstance(UnitOfWork.class).end();
144-
fail("a result was returned! rollback sure didnt happen!!!");
145-
} catch (NoResultException e) {
146-
}
140+
assertThrows(
141+
NoResultException.class,
142+
() ->
143+
em.createQuery("from JpaTestEntity where text = :text")
144+
.setParameter("text", TRANSIENT_UNIQUE_TEXT)
145+
.getSingleResult());
146+
injector.getInstance(UnitOfWork.class).end();
147+
}
148+
149+
public void testSimpleTransactionRollbackPerformedManuallyWithoutException() {
150+
injector.getInstance(TransactionalObject.class).runOperationInTxnWithManualRollback();
151+
152+
EntityManager em = injector.getInstance(EntityManager.class);
153+
assertFalse(
154+
"Session was not closed by transactional service (rollback didnt happen?)",
155+
em.getTransaction().isActive());
156+
157+
assertThrows(
158+
NoResultException.class,
159+
() ->
160+
em.createQuery("from JpaTestEntity where text = :text")
161+
.setParameter("text", TRANSIENT_UNIQUE_TEXT)
162+
.getSingleResult());
163+
injector.getInstance(UnitOfWork.class).end();
164+
}
165+
166+
public void testSimpleTransactionRollbackOnlySetWithoutException() {
167+
injector.getInstance(TransactionalObject.class).runOperationInTxnWithRollbackOnlySet();
168+
169+
EntityManager em = injector.getInstance(EntityManager.class);
170+
assertFalse(
171+
"Session was not closed by transactional service (rollback didnt happen?)",
172+
em.getTransaction().isActive());
173+
174+
assertThrows(
175+
NoResultException.class,
176+
() ->
177+
em.createQuery("from JpaTestEntity where text = :text")
178+
.setParameter("text", TRANSIENT_UNIQUE_TEXT)
179+
.getSingleResult());
180+
injector.getInstance(UnitOfWork.class).end();
147181
}
148182

149183
public static class TransactionalObject {
@@ -185,5 +219,23 @@ public void runOperationInTxnThrowingUnchecked() {
185219

186220
throw new IllegalStateException();
187221
}
222+
223+
@Transactional
224+
public void runOperationInTxnWithManualRollback() {
225+
JpaTestEntity entity = new JpaTestEntity();
226+
entity.setText(TRANSIENT_UNIQUE_TEXT);
227+
em.persist(entity);
228+
229+
em.getTransaction().rollback();
230+
}
231+
232+
@Transactional
233+
public void runOperationInTxnWithRollbackOnlySet() {
234+
JpaTestEntity entity = new JpaTestEntity();
235+
entity.setText(TRANSIENT_UNIQUE_TEXT);
236+
em.persist(entity);
237+
238+
em.getTransaction().setRollbackOnly();
239+
}
188240
}
189241
}

0 commit comments

Comments
 (0)