From 68bc86c7e198b8e3e444c5028d97edb14e5c4179 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Mon, 22 Sep 2025 21:19:06 +0200 Subject: [PATCH] clarify the semantics of rollbackOn/dontRollbackOn for #223 --- .../jakarta/transaction/Transactional.java | 61 +++++++++++-------- spec/src/main/asciidoc/Transactions.adoc | 37 +++++++---- 2 files changed, 61 insertions(+), 37 deletions(-) diff --git a/api/src/main/java/jakarta/transaction/Transactional.java b/api/src/main/java/jakarta/transaction/Transactional.java index 63bfb0d..513e891 100644 --- a/api/src/main/java/jakarta/transaction/Transactional.java +++ b/api/src/main/java/jakarta/transaction/Transactional.java @@ -51,21 +51,23 @@ *

* *

- * By default checked exceptions do not result in the transactional interceptor marking the transaction for rollback and - * instances of RuntimeException and its subclasses do. This default behavior can be modified by specifying exceptions - * that result in the interceptor marking the transaction for rollback and/or exceptions that do not result in rollback. + * By default, a Transactional interceptor marks the transaction for rollback when it intercepts an exception assignable + * to RuntimeException. Checked exceptions are considered application exceptions and do not, by default, cause + * the interceptor to mark the transaction for rollback. *

*

- * The rollbackOn element can be set to indicate exceptions that must cause the interceptor to mark the transaction for - * rollback. + * This default behavior can be modified by specifying additional types that cause the interceptor to mark the + * transaction for rollback and/or types that do not cause the interceptor to mark the transaction for rollback. *

+ * *

- * Conversely, the dontRollbackOn element can be set to indicate exceptions that must not cause the interceptor to mark - * the transaction for rollback. - *

- *

- * When a class is specified for either of these elements, the designated behavior applies to subclasses of that class - * as well. If both elements are specified, dontRollbackOn takes precedence. + * If an exception is an instance of Error, the behavior is undefined. A Transactional interceptor is not required to + * catch Errors, and so portable applications should not depend on the behavior of the interceptor when an Error occurs. *

* * @version Jakarta Transactions 2.0 @@ -169,27 +171,36 @@ public enum TxType { } /** - * The rollbackOn element can be set to indicate exceptions that must cause the interceptor to mark the transaction for - * rollback. Conversely, the dontRollbackOn element can be set to indicate exceptions that must not cause the - * interceptor to mark the transaction for rollback. When a class is specified for either of these elements, the - * designated behavior applies to subclasses of that class as well. If both elements are specified, dontRollbackOn takes - * precedence. + *

+ * Specifies a list of class and interface types which cause the interceptor to mark the transaction for rollback + * when an exception assignable to one of the listed types is intercepted. + *

+ * * - * @return Class[] of Exceptions + * @return A list of Class objects representing the class and interface types. */ @Nonbinding - public Class[] rollbackOn() default {}; + Class[] rollbackOn() default {}; /** - * The dontRollbackOn element can be set to indicate exceptions that must not cause the interceptor to mark the - * transaction for rollback. Conversely, the rollbackOn element can be set to indicate exceptions that must cause the - * interceptor to mark the transaction for rollback. When a class is specified for either of these elements, the - * designated behavior applies to subclasses of that class as well. If both elements are specified, dontRollbackOn takes - * precedence. + *

+ * Specifies a list of class and interface types which do not cause the interceptor to mark the transaction for + * rollback when an exception assignable to one of the listed types is intercepted. If an exception is an instance + * of one of the listed types, the interceptor must not mark the transaction for rollback, even if the exception is + * also an instance of RuntimeException or of a type listed in rollbackOn. + *

* - * @return Class[] of Exceptions + * @return A list of Class objects representing the class and interface types. */ @Nonbinding - public Class[] dontRollbackOn() default {}; + Class[] dontRollbackOn() default {}; } diff --git a/spec/src/main/asciidoc/Transactions.adoc b/spec/src/main/asciidoc/Transactions.adoc index f0252ac..2aaf0d5 100644 --- a/spec/src/main/asciidoc/Transactions.adoc +++ b/spec/src/main/asciidoc/Transactions.adoc @@ -1071,18 +1071,31 @@ If called inside a transaction context, a `TransactionalException` with a nested `InvalidTransactionException` must be thrown -By default checked exceptions do not result -in the transactional interceptor marking the transaction for rollback -and instances of `RuntimeException` and its subclasses do. This default -behavior can be modified by specifying exceptions that result in the -interceptor marking the transaction for rollback and/or exceptions that -do not result in rollback. The `rollbackOn` element can be set to indicate -exceptions that must cause the interceptor to mark the transaction for -rollback. Conversely, the `dontRollbackOn` element can be set to -indicate exceptions that must not cause the interceptor to mark the -transaction for rollback. When a class is specified for either of these -elements, the designated behavior applies to subclasses of that class as -well. If both elements are specified, `dontRollbackOn` takes precedence. +By default, a `Transactional` interceptor marks the transaction for +rollback when it intercepts an exception assignable to `RuntimeException`. +Checked exceptions are considered _application exceptions_ and do not, +by default, cause the interceptor to mark the transaction for rollback. + +This default behavior can be modified by specifying additional types that +cause the interceptor to mark the transaction for rollback and/or types +that do not cause the interceptor to mark the transaction for rollback. + +* If an exception is an instance of a type listed by `rollbackOn`, and + also of `Exception`, and if the exception is not also an instance of + a type listed in `dontRollbackOn`, the interceptor must mark the + transaction for rollback. +* If an exception is an instance of a type listed by `dontRollbackOn`, + the interceptor must not mark the transaction for rollback, even if + the exception is also an instance of `RuntimeException` or of a type + listed in `rollbackOn`. + +If an exception is an instance of `Error`, the behavior is undefined. +A `Transactional` interceptor is not required to catch Errors, and so +portable applications should not depend on the behavior of the interceptor +when an `Error` occurs. + +The types specified by `rollbackOn` and `dontRollbackOn` may be class +or interface types. The following example will override behavior for application exceptions, causing the transaction to be marked for