spring-projects / spring-projects/spring-framework
Add support for Either besides Try in TransactionAspectSupport in spring-tx
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 60.2k
- Forks
- 38.8k
- Avg merge
- 5d 2h
- Merged PRs (30d)
- 27
Description
Description
Spring Framework already supports Vavr's Try type for transaction rollback decisions in TransactionAspectSupport. This proposal requests adding equivalent support for Vavr's Either type, which is widely used for railway-oriented programming and functional error handling.
Motivation
Either<L, R> is a common pattern for representing success (Right) or failure (Left) without throwing exceptions. It's the preferred approach for:
- Railway-oriented programming
- Explicit error handling in functional pipelines
- Domain-driven design where errors are domain concepts, not exceptions
Currently, a method like this will commit even when returning a failure:
@Transactional
public Either<PaymentError, Receipt> processPayment(PaymentRequest request) {
return validateRequest(request)
.flatMap(this::checkFunds)
.flatMap(this::executeTransfer);
// Returns Either.Left(InsufficientFunds) → transaction COMMITS (unexpected!)
}
Users expect Either.Left to trigger a rollback, similar to how Try.Failure does.
Proposed Change
Add Either support in TransactionAspectSupport.VavrDelegate, mirroring the existing Try implementation:
In invokeWithinTransaction() (~line 380):
// Existing Try support
else if (vavrPresent && VavrDelegate.isVavrTry(retVal)) {
retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
}
// Proposed Either support
else if (vavrPresent && VavrDelegate.isVavrEither(retVal)) {
retVal = VavrDelegate.evaluateEitherLeft(retVal, txAttr, status);
}
In VavrDelegate inner class:
public static boolean isVavrEither(@Nullable Object retVal) {
return (retVal instanceof Either<?, ?> either && either.isLeft());
}
public static Object evaluateEitherLeft(Object retVal,
@Nullable TransactionAttribute txAttr, TransactionStatus status) {
return ((Either<?, ?>) retVal).peekLeft(left -> {
if (left instanceof Throwable throwable) {
if (txAttr != null && txAttr.rollbackOn(throwable)) {
status.setRollbackOnly();
}
} else {
// Non-Throwable Left: rollback by default
status.setRollbackOnly();
}
});
}
Behavior
| Return Value | Transaction Outcome |
|---|---|
Either.Right(value) |
Commit |
Either.Left(throwable) |
Rollback if txAttr.rollbackOn(throwable) matches |
Either.Left(nonThrowable) |
Rollback (default) |
Scope
This proposal (Phase 1):
- Basic Either.Left → rollback support
- Consistent with existing Try.Failure behavior
- Minimal change (~30-50 lines)
Future enhancement (Phase 2):
- Custom rollback rules for non-Throwable types (
rollbackForWithEitherattribute) - Fine-grained control over which Left values trigger rollback
Impact
- No breaking changes - additive only
- No new dependencies - Vavr is already optional
- Consistent - matches existing Try support pattern
- Low risk - isolated to VavrDelegate
Alternatives Considered
- Do nothing - Users must wrap Either in Try or throw exceptions (breaks functional style)
- Custom TransactionInterceptor - Requires significant boilerplate for each project
- AOP around advice - Happens after commit, too late for rollback
References
- Existing Try support:
TransactionAspectSupport.VavrDelegate.evaluateTryFailure() - Vavr Either documentation: https://docs.vavr.io/#_either
- Railway-oriented programming: https://fsharpforfunandprofit.com/rop/
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in TransactionAspectSupport.invokeWithinTransaction() and read the existing VavrDelegate.evaluateTryFailure() implementation. Compare the requested Either behavior with the existing Try handling and verify the stated Right, Throwable Left, and non-Throwable Left transaction outcomes. Done means Either.Left handling is integrated without new dependencies and remains consistent with the proposed rollback rules.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- backend
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100