jsr342-experts@javaee-spec.java.net

[jsr342-experts] transactional interceptors and exceptions

From: Linda DeMichiel <linda.demichiel_at_oracle.com>
Date: Thu, 12 Jul 2012 18:00:31 -0700

We'd like to close out the remaining open issue as to how to
specify the behavior of transactional interceptors when an
exception is thrown that reaches such an interceptor.

After tallying and weighing the responses that we received from
polling this group, from our other Java EE specleads, and from members
of the community, we propose that we take the "D3 S3C A1" approach
-- which is consistent with the majority of the opinions we received.
(To refresh your memory, please see Bill's earlier message, appended below.)


The proposal is the following:

By default, "application exceptions" (i.e., checked exceptions /
instances of Exception and its subclasses other than RuntimeException)
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 overridden via the Transactional
annotation. More specifically, we propose adding to the
Transactional annotation an element to specify additional
exceptions that result in the interceptor marking the
transaction for rollback and an element to specify exceptions
that do not cause the interceptor to mark the transaction for rollback.

For example:

@Inherited
@InterceptorBinding
@Target({TYPE, METHOD})
@Retention(RUNTIME)
public @interface Transactional {
    TxType value() default TxType.REQUIRED;
    Class[] rollbackOn() default {};
    Class[] dontRollbackOn() default {};
}

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.


Examples:

@Transactional(rollbackOn={Exception.class})

will override behavior for application exceptions, causing the
transaction to be marked for rollback for all application exceptions.


@Transactional(dontRollbackOn={IllegalStateException})

will prevent transactions from being marked for rollback by the
interceptor when an IllegalStateException or any of its subclasses
reaches the interceptor.


@Transactional(
   rollbackOn={SQLException.class},
   dontRollbackOn={SQLWarning.class}
)

will cause the transaction to be marked for rollback for all
runtime exceptions and all SQLException types except for SQLWarning.


Note that we are assuming that there is no special, built-in knowledge
about EJB application exceptions (i.e., runtime exceptions annotated
with @ApplicationException). As far as the interceptor is concerned,
these would be treated just as any other runtime exceptions unless
otherwise specified.

Please let us know if you have any additional feedback on this.

thanks!

-Linda

--------------------------------


On 1/30/2012 12:40 PM, Bill Shannon wrote:
> One of the issues with the new transactional annotations we're
> proposing is how to handle exceptions that are thrown out of a
> transactional method.
>
> The first choice is, what should the default behavior be?
> We have these options:
>
> D1. By default, exceptions don't effect the current transaction.
> D2. By default, exceptions cause the current transaction to be
> marked for rollback.
> D3. By default, runtime exceptions cause the current transaction to be
> marked for rollback; checked exceptions do not effect the current
> transaction.
>
> After deciding on the default behavior, we have these choices for
> overriding the default:
>
> S1. You can't override the default.
> S2a. You can override the default by annotating exceptions that
> should cause rollback. (E.g., with @ApplicationException)
> S2b. You can override the default by annotating exceptions that
> should not cause rollback.
> S2c. You can override the default by annotating exceptions that
> should cause rollback and by annotating exceptions that should
> not cause rollback. (E.g., with a "rollback" element in
> @ApplicationException)
> S3a. You can override the default by annotating class or methods
> with a list of exceptions that should cause rollback.
> S3b. You can override the default by annotating class or methods
> with a list of exceptions that should not cause rollback.
> S3c. You can override the default by annotating class or methods
> with a list of exceptions that should cause rollback, and a
> list of exceptions that should not cause rollback.
>
> The S2c and S3c options have these additional options:
>
> A1. The rollback behavior is an element(s) of the base annotation.
> A2. The rollback behavior is a separate annotation(s).
>
> (Note that S2 and S3 are not mutually exclusive.)
>
> In all cases, the behavior for a given exception is determined by
> looking for an annotation or specification for that particular
> exception and if none is found traversing the superclass chain.
> That is, the exception behavior is always "inherited".
>
>
> My understanding is that Spring supports D3 S3c A1.
> (In addition, Spring allows specifying the exceptions as either
> Class objects or String names, which seems like overkill.)
>
> EJB supports D3 S2c A1 for local beans.
>
> I believe Reza was suggesting D3 S2c S3c A1.
>
> I believe David was suggesting D1 S3a A2.
>
> Our goal with these new transactional annotations was to come up
> with something that was simple, where "simple" means both "has
> few concepts" and "is easily understood by developers". In addition
> to being simple, it needs to satisfy a large percentage of the use cases.
>
> The simplest is D1 S1, but I don't think that matches what developers
> will expect.
>
> Given the prevalence of D3 in existing systems, D3 S1 would be very
> simple. Unfortunately, we're told that many developers are moving
> towards using runtime exceptions for everything, so D3 S2b would be
> a relatively simple approach.
>
> The major advantage I see for the S3 options is that they allow you
> to more easily override the default behavior for "system" exceptions.
> For example, if your method throws IllegalArgumentException in a case
> where it knows that it hasn't modified the state of the transaction,
> you might like that exception to *not* cause the transaction to be
> marked for rollback. With S2, you would have to subclass the exception
> and mark the subclass. But of course that does have the advantage
> that other uses of that exception in methods you call have the default
> behavior.
>
> Which options do you prefer?