Skip to content

Commit cc3948e

Browse files
Jaeyoung22jhoeller
authored andcommitted
feat: Implemented to throw a runtime error if a class has @transactional
1 parent e3cf23d commit cc3948e

File tree

2 files changed

+57
-0
lines changed

2 files changed

+57
-0
lines changed

Diff for: spring-tx/src/main/java/org/springframework/transaction/annotation/RestrictedTransactionalEventListenerFactory.java

+5
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ public class RestrictedTransactionalEventListenerFactory extends TransactionalEv
3838
@Override
3939
public ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method) {
4040
Transactional txAnn = AnnotatedElementUtils.findMergedAnnotation(method, Transactional.class);
41+
42+
if (txAnn == null) {
43+
txAnn = AnnotatedElementUtils.findMergedAnnotation(type, Transactional.class);
44+
}
45+
4146
if (txAnn != null) {
4247
Propagation propagation = txAnn.propagation();
4348
if (propagation != Propagation.REQUIRES_NEW && propagation != Propagation.NOT_SUPPORTED) {

Diff for: spring-tx/src/test/java/org/springframework/transaction/event/TransactionalApplicationListenerMethodAdapterTests.java

+52
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.springframework.transaction.annotation.Propagation;
2929
import org.springframework.transaction.annotation.RestrictedTransactionalEventListenerFactory;
3030
import org.springframework.transaction.annotation.Transactional;
31+
import org.springframework.transaction.event.TransactionalApplicationListenerMethodAdapterTests.SampleEvents.SampleEventsWithTransactionalAnnotation;
3132
import org.springframework.transaction.support.TransactionSynchronization;
3233
import org.springframework.transaction.support.TransactionSynchronizationManager;
3334
import org.springframework.util.ClassUtils;
@@ -157,6 +158,34 @@ void withAsyncTransactionalAnnotation() {
157158
assertThatNoException().isThrownBy(() -> factory.createApplicationListener("test", SampleEvents.class, m));
158159
}
159160

161+
@Test
162+
void withTransactionalAnnotationOnEnclosingClass() {
163+
RestrictedTransactionalEventListenerFactory factory = new RestrictedTransactionalEventListenerFactory();
164+
Method m = ReflectionUtils.findMethod(SampleEvents.SampleEventsWithTransactionalAnnotation.class, "defaultPhase", String.class);
165+
assertThatIllegalStateException().isThrownBy(() -> factory.createApplicationListener("test", SampleEvents.SampleEventsWithTransactionalAnnotation.class, m));
166+
}
167+
168+
@Test
169+
void withTransactionalRequiresNewAnnotationAndTransactionalAnnotationOnEnclosingClass() {
170+
RestrictedTransactionalEventListenerFactory factory = new RestrictedTransactionalEventListenerFactory();
171+
Method m = ReflectionUtils.findMethod(SampleEvents.SampleEventsWithTransactionalAnnotation.class, "withTransactionalRequiresNewAnnotation", String.class);
172+
assertThatNoException().isThrownBy(() -> factory.createApplicationListener("test", SampleEvents.SampleEventsWithTransactionalAnnotation.class, m));
173+
}
174+
175+
@Test
176+
void withTransactionalNotSupportedAnnotationAndTransactionalAnnotationOnEnclosingClass() {
177+
RestrictedTransactionalEventListenerFactory factory = new RestrictedTransactionalEventListenerFactory();
178+
Method m = ReflectionUtils.findMethod(SampleEvents.SampleEventsWithTransactionalAnnotation.class, "withTransactionalNotSupportedAnnotation", String.class);
179+
assertThatNoException().isThrownBy(() -> factory.createApplicationListener("test", SampleEvents.SampleEventsWithTransactionalAnnotation.class, m));
180+
}
181+
182+
@Test
183+
void withAsyncTransactionalAnnotationAndTransactionalAnnotationOnEnclosingClass() {
184+
RestrictedTransactionalEventListenerFactory factory = new RestrictedTransactionalEventListenerFactory();
185+
Method m = ReflectionUtils.findMethod(SampleEvents.SampleEventsWithTransactionalAnnotation.class, "withAsyncTransactionalAnnotation", String.class);
186+
assertThatNoException().isThrownBy(() -> factory.createApplicationListener("test", SampleEvents.SampleEventsWithTransactionalAnnotation.class, m));
187+
}
188+
160189

161190
private static void assertPhase(Method method, TransactionPhase expected) {
162191
assertThat(method).as("Method must not be null").isNotNull();
@@ -248,6 +277,29 @@ public void withTransactionalNotSupportedAnnotation(String data) {
248277
@Async @Transactional(propagation = Propagation.REQUIRES_NEW)
249278
public void withAsyncTransactionalAnnotation(String data) {
250279
}
280+
281+
@Transactional
282+
static class SampleEventsWithTransactionalAnnotation {
283+
284+
@TransactionalEventListener
285+
public void defaultPhase(String data) {
286+
}
287+
288+
@TransactionalEventListener
289+
@Transactional(propagation = Propagation.REQUIRES_NEW)
290+
public void withTransactionalRequiresNewAnnotation(String data) {
291+
}
292+
293+
@TransactionalEventListener
294+
@Transactional(propagation = Propagation.NOT_SUPPORTED)
295+
public void withTransactionalNotSupportedAnnotation(String data) {
296+
}
297+
298+
@TransactionalEventListener
299+
@Async @Transactional(propagation = Propagation.REQUIRES_NEW)
300+
public void withAsyncTransactionalAnnotation(String data) {
301+
}
302+
}
251303
}
252304

253305
}

0 commit comments

Comments
 (0)