Trigger rollback for (Completable)Future exception on method return

Closes gh-30018
This commit is contained in:
Juergen Hoeller
2023-05-03 10:03:31 +02:00
parent c1014f5989
commit dd871e0d8c
2 changed files with 99 additions and 27 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
package org.springframework.transaction.annotation;
import java.time.Duration;
import java.util.concurrent.CompletableFuture;
import io.vavr.control.Try;
import org.junit.jupiter.api.Test;
@@ -57,7 +58,6 @@ public class AnnotationTransactionInterceptorTests {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new TestClassLevelOnly());
proxyFactory.addAdvice(this.ti);
TestClassLevelOnly proxy = (TestClassLevelOnly) proxyFactory.getProxy();
proxy.doSomething();
@@ -78,7 +78,6 @@ public class AnnotationTransactionInterceptorTests {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new TestWithSingleMethodOverride());
proxyFactory.addAdvice(this.ti);
TestWithSingleMethodOverride proxy = (TestWithSingleMethodOverride) proxyFactory.getProxy();
proxy.doSomething();
@@ -99,7 +98,6 @@ public class AnnotationTransactionInterceptorTests {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new TestWithSingleMethodOverrideInverted());
proxyFactory.addAdvice(this.ti);
TestWithSingleMethodOverrideInverted proxy = (TestWithSingleMethodOverrideInverted) proxyFactory.getProxy();
proxy.doSomething();
@@ -120,7 +118,6 @@ public class AnnotationTransactionInterceptorTests {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new TestWithMultiMethodOverride());
proxyFactory.addAdvice(this.ti);
TestWithMultiMethodOverride proxy = (TestWithMultiMethodOverride) proxyFactory.getProxy();
proxy.doSomething();
@@ -141,7 +138,6 @@ public class AnnotationTransactionInterceptorTests {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new TestWithExceptions());
proxyFactory.addAdvice(this.ti);
TestWithExceptions proxy = (TestWithExceptions) proxyFactory.getProxy();
assertThatIllegalStateException().isThrownBy(
@@ -158,7 +154,6 @@ public class AnnotationTransactionInterceptorTests {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new TestWithExceptions());
proxyFactory.addAdvice(this.ti);
TestWithExceptions proxy = (TestWithExceptions) proxyFactory.getProxy();
assertThatException()
@@ -171,7 +166,6 @@ public class AnnotationTransactionInterceptorTests {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new TestWithExceptions());
proxyFactory.addAdvice(this.ti);
TestWithExceptions proxy = (TestWithExceptions) proxyFactory.getProxy();
assertThatException()
@@ -184,7 +178,6 @@ public class AnnotationTransactionInterceptorTests {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new TestWithReactive());
proxyFactory.addAdvice(new TransactionInterceptor(rtm, this.source));
TestWithReactive proxy = (TestWithReactive) proxyFactory.getProxy();
StepVerifier.withVirtualTime(proxy::monoSuccess).thenAwait(Duration.ofSeconds(10)).verifyComplete();
@@ -196,7 +189,6 @@ public class AnnotationTransactionInterceptorTests {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new TestWithReactive());
proxyFactory.addAdvice(new TransactionInterceptor(rtm, this.source));
TestWithReactive proxy = (TestWithReactive) proxyFactory.getProxy();
proxy.monoFailure().as(StepVerifier::create).verifyError();
@@ -208,7 +200,6 @@ public class AnnotationTransactionInterceptorTests {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new TestWithReactive());
proxyFactory.addAdvice(new TransactionInterceptor(rtm, this.source));
TestWithReactive proxy = (TestWithReactive) proxyFactory.getProxy();
StepVerifier.withVirtualTime(proxy::monoSuccess).thenAwait(Duration.ofSeconds(1)).thenCancel().verify();
@@ -220,7 +211,6 @@ public class AnnotationTransactionInterceptorTests {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new TestWithReactive());
proxyFactory.addAdvice(new TransactionInterceptor(rtm, this.source));
TestWithReactive proxy = (TestWithReactive) proxyFactory.getProxy();
StepVerifier.withVirtualTime(proxy::fluxSuccess).thenAwait(Duration.ofSeconds(10)).expectNextCount(1).verifyComplete();
@@ -232,7 +222,6 @@ public class AnnotationTransactionInterceptorTests {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new TestWithReactive());
proxyFactory.addAdvice(new TransactionInterceptor(rtm, this.source));
TestWithReactive proxy = (TestWithReactive) proxyFactory.getProxy();
proxy.fluxFailure().as(StepVerifier::create).verifyError();
@@ -244,19 +233,61 @@ public class AnnotationTransactionInterceptorTests {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new TestWithReactive());
proxyFactory.addAdvice(new TransactionInterceptor(rtm, this.source));
TestWithReactive proxy = (TestWithReactive) proxyFactory.getProxy();
StepVerifier.withVirtualTime(proxy::fluxSuccess).thenAwait(Duration.ofSeconds(1)).thenCancel().verify();
assertReactiveGetTransactionAndRollbackCount(1);
}
@Test
public void withCompletableFutureSuccess() {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new TestWithCompletableFuture());
proxyFactory.addAdvice(this.ti);
TestWithCompletableFuture proxy = (TestWithCompletableFuture) proxyFactory.getProxy();
proxy.doSomething();
assertGetTransactionAndCommitCount(1);
}
@Test
public void withCompletableFutureRuntimeException() {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new TestWithCompletableFuture());
proxyFactory.addAdvice(this.ti);
TestWithCompletableFuture proxy = (TestWithCompletableFuture) proxyFactory.getProxy();
proxy.doSomethingErroneous();
assertGetTransactionAndRollbackCount(1);
}
@Test
public void withCompletableFutureCheckedException() {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new TestWithCompletableFuture());
proxyFactory.addAdvice(this.ti);
TestWithCompletableFuture proxy = (TestWithCompletableFuture) proxyFactory.getProxy();
proxy.doSomethingErroneousWithCheckedException();
assertGetTransactionAndCommitCount(1);
}
@Test
public void withCompletableFutureCheckedExceptionAndRollbackRule() {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new TestWithCompletableFuture());
proxyFactory.addAdvice(this.ti);
TestWithCompletableFuture proxy = (TestWithCompletableFuture) proxyFactory.getProxy();
proxy.doSomethingErroneousWithCheckedExceptionAndRollbackRule();
assertGetTransactionAndRollbackCount(1);
}
@Test
public void withVavrTrySuccess() {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new TestWithVavrTry());
proxyFactory.addAdvice(this.ti);
TestWithVavrTry proxy = (TestWithVavrTry) proxyFactory.getProxy();
proxy.doSomething();
@@ -268,7 +299,6 @@ public class AnnotationTransactionInterceptorTests {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new TestWithVavrTry());
proxyFactory.addAdvice(this.ti);
TestWithVavrTry proxy = (TestWithVavrTry) proxyFactory.getProxy();
proxy.doSomethingErroneous();
@@ -280,7 +310,6 @@ public class AnnotationTransactionInterceptorTests {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new TestWithVavrTry());
proxyFactory.addAdvice(this.ti);
TestWithVavrTry proxy = (TestWithVavrTry) proxyFactory.getProxy();
proxy.doSomethingErroneousWithCheckedException();
@@ -292,7 +321,6 @@ public class AnnotationTransactionInterceptorTests {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new TestWithVavrTry());
proxyFactory.addAdvice(this.ti);
TestWithVavrTry proxy = (TestWithVavrTry) proxyFactory.getProxy();
proxy.doSomethingErroneousWithCheckedExceptionAndRollbackRule();
@@ -305,7 +333,6 @@ public class AnnotationTransactionInterceptorTests {
proxyFactory.setTarget(new TestWithInterfaceImpl());
proxyFactory.addInterface(TestWithInterface.class);
proxyFactory.addAdvice(this.ti);
TestWithInterface proxy = (TestWithInterface) proxyFactory.getProxy();
proxy.doSomething();
@@ -330,7 +357,6 @@ public class AnnotationTransactionInterceptorTests {
proxyFactory.setTarget(new SomeServiceImpl());
proxyFactory.addInterface(SomeService.class);
proxyFactory.addAdvice(this.ti);
SomeService someService = (SomeService) proxyFactory.getProxy();
someService.bar();
@@ -349,7 +375,6 @@ public class AnnotationTransactionInterceptorTests {
proxyFactory.setTarget(new OtherServiceImpl());
proxyFactory.addInterface(OtherService.class);
proxyFactory.addAdvice(this.ti);
OtherService otherService = (OtherService) proxyFactory.getProxy();
otherService.foo();
@@ -366,7 +391,6 @@ public class AnnotationTransactionInterceptorTests {
proxyFactory.setTarget(targetFactory.getProxy());
proxyFactory.addInterface(TestWithInterface.class);
proxyFactory.addAdvice(this.ti);
TestWithInterface proxy = (TestWithInterface) proxyFactory.getProxy();
proxy.doSomething();
@@ -395,7 +419,6 @@ public class AnnotationTransactionInterceptorTests {
proxyFactory.setTarget(targetFactory.getProxy());
proxyFactory.addInterface(TestWithInterface.class);
proxyFactory.addAdvice(this.ti);
TestWithInterface proxy = (TestWithInterface) proxyFactory.getProxy();
proxy.doSomething();
@@ -544,6 +567,7 @@ public class AnnotationTransactionInterceptorTests {
}
}
@Transactional
public static class TestWithReactive {
@@ -564,6 +588,37 @@ public class AnnotationTransactionInterceptorTests {
}
}
@Transactional
public static class TestWithCompletableFuture {
public CompletableFuture<String> doSomething() {
assertThat(TransactionSynchronizationManager.isActualTransactionActive()).isTrue();
assertThat(TransactionSynchronizationManager.isCurrentTransactionReadOnly()).isFalse();
return CompletableFuture.completedFuture("ok");
}
public CompletableFuture<String> doSomethingErroneous() {
assertThat(TransactionSynchronizationManager.isActualTransactionActive()).isTrue();
assertThat(TransactionSynchronizationManager.isCurrentTransactionReadOnly()).isFalse();
return CompletableFuture.failedFuture(new IllegalStateException());
}
public CompletableFuture<String> doSomethingErroneousWithCheckedException() {
assertThat(TransactionSynchronizationManager.isActualTransactionActive()).isTrue();
assertThat(TransactionSynchronizationManager.isCurrentTransactionReadOnly()).isFalse();
return CompletableFuture.failedFuture(new Exception());
}
@Transactional(rollbackFor = Exception.class)
public CompletableFuture<String> doSomethingErroneousWithCheckedExceptionAndRollbackRule() {
assertThat(TransactionSynchronizationManager.isActualTransactionActive()).isTrue();
assertThat(TransactionSynchronizationManager.isCurrentTransactionReadOnly()).isFalse();
return CompletableFuture.failedFuture(new Exception());
}
}
@Transactional
public static class TestWithVavrTry {