Skip to content

Commit 001fc8e

Browse files
committed
Add early support for JTA 2.1 read-only attribute
Closes gh-35633
1 parent 43c13ca commit 001fc8e

File tree

3 files changed

+43
-0
lines changed

3 files changed

+43
-0
lines changed

spring-tx/src/main/java/org/springframework/transaction/annotation/JtaTransactionAnnotationParser.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes a
7878
}
7979
rbta.setRollbackRules(rollbackRules);
8080

81+
if (attributes.containsKey("readOnly")) { // JTA 2.1
82+
rbta.setReadOnly(attributes.getBoolean("readOnly"));
83+
}
84+
8185
return rbta;
8286
}
8387

spring-tx/src/main/java/org/springframework/transaction/jta/JtaTransactionManager.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import java.io.IOException;
2020
import java.io.ObjectInputStream;
2121
import java.io.Serializable;
22+
import java.lang.reflect.InvocationTargetException;
23+
import java.lang.reflect.Method;
2224
import java.util.List;
2325
import java.util.Properties;
2426

@@ -52,6 +54,8 @@
5254
import org.springframework.transaction.support.DefaultTransactionStatus;
5355
import org.springframework.transaction.support.TransactionSynchronization;
5456
import org.springframework.util.Assert;
57+
import org.springframework.util.ClassUtils;
58+
import org.springframework.util.ReflectionUtils;
5559
import org.springframework.util.StringUtils;
5660

5761
/**
@@ -139,6 +143,10 @@ public class JtaTransactionManager extends AbstractPlatformTransactionManager
139143
"java:comp/TransactionSynchronizationRegistry";
140144

141145

146+
// JTA 2.1 UserTransaction#setReadOnly(boolean) method available?
147+
private static final @Nullable Method setReadOnlyMethod =
148+
ClassUtils.getMethodIfAvailable(UserTransaction.class, "setReadOnly", boolean.class);
149+
142150
private transient JndiTemplate jndiTemplate = new JndiTemplate();
143151

144152
private transient @Nullable UserTransaction userTransaction;
@@ -858,6 +866,12 @@ protected void doJtaBegin(JtaTransactionObject txObject, TransactionDefinition d
858866
applyIsolationLevel(txObject, definition.getIsolationLevel());
859867
int timeout = determineTimeout(definition);
860868
applyTimeout(txObject, timeout);
869+
870+
if (definition.isReadOnly()) {
871+
setReadOnlyIfPossible(txObject.getUserTransaction(), true);
872+
txObject.resetReadOnly = true;
873+
}
874+
861875
txObject.getUserTransaction().begin();
862876
}
863877

@@ -904,6 +918,21 @@ protected void applyTimeout(JtaTransactionObject txObject, int timeout) throws S
904918
}
905919
}
906920

921+
private void setReadOnlyIfPossible(UserTransaction ut, boolean readOnly) throws SystemException {
922+
if (setReadOnlyMethod != null) {
923+
try {
924+
setReadOnlyMethod.invoke(ut, readOnly);
925+
}
926+
catch (Exception ex) {
927+
if (ex instanceof InvocationTargetException ute &&
928+
ute.getTargetException() instanceof SystemException se) {
929+
throw se;
930+
}
931+
ReflectionUtils.handleReflectionException(ex);
932+
}
933+
}
934+
}
935+
907936

908937
@Override
909938
protected Object doSuspend(Object transaction) {
@@ -1161,6 +1190,14 @@ else if (getTransactionManager() != null) {
11611190
@Override
11621191
protected void doCleanupAfterCompletion(Object transaction) {
11631192
JtaTransactionObject txObject = (JtaTransactionObject) transaction;
1193+
if (txObject.resetReadOnly) {
1194+
try {
1195+
setReadOnlyIfPossible(txObject.getUserTransaction(), false);
1196+
}
1197+
catch (SystemException ex) {
1198+
logger.debug("Failed to reset read-only flag after after JTA completion", ex);
1199+
}
1200+
}
11641201
if (txObject.resetTransactionTimeout) {
11651202
try {
11661203
txObject.getUserTransaction().setTransactionTimeout(0);

spring-tx/src/main/java/org/springframework/transaction/jta/JtaTransactionObject.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ public class JtaTransactionObject implements SmartTransactionObject {
4141

4242
boolean resetTransactionTimeout = false;
4343

44+
boolean resetReadOnly = false;
45+
4446

4547
/**
4648
* Create a new JtaTransactionObject for the given JTA UserTransaction.

0 commit comments

Comments
 (0)