Skip to content

Commit 4b09631

Browse files
committed
Sort detected PersistenceExceptionTranslator
Apply sorting on detected PersistenceExceptionTranslators. Relates to spring-projects#24634
1 parent ac11acb commit 4b09631

File tree

2 files changed

+81
-2
lines changed

2 files changed

+81
-2
lines changed

spring-tx/src/main/java/org/springframework/dao/support/PersistenceExceptionTranslationInterceptor.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616

1717
package org.springframework.dao.support;
1818

19+
import java.util.ArrayList;
20+
import java.util.Comparator;
21+
import java.util.List;
1922
import java.util.Map;
2023

2124
import org.aopalliance.intercept.MethodInterceptor;
@@ -27,6 +30,8 @@
2730
import org.springframework.beans.factory.BeanFactoryUtils;
2831
import org.springframework.beans.factory.InitializingBean;
2932
import org.springframework.beans.factory.ListableBeanFactory;
33+
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
34+
import org.springframework.core.OrderComparator;
3035
import org.springframework.lang.Nullable;
3136
import org.springframework.util.Assert;
3237
import org.springframework.util.ReflectionUtils;
@@ -167,8 +172,21 @@ protected PersistenceExceptionTranslator detectPersistenceExceptionTranslators(L
167172
// Find all translators, being careful not to activate FactoryBeans.
168173
Map<String, PersistenceExceptionTranslator> pets = BeanFactoryUtils.beansOfTypeIncludingAncestors(
169174
beanFactory, PersistenceExceptionTranslator.class, false, false);
175+
176+
List<PersistenceExceptionTranslator> translators = new ArrayList<>(pets.values());
177+
if (translators.size() > 1) {
178+
Comparator<Object> comparatorToUse = null;
179+
if (beanFactory instanceof DefaultListableBeanFactory) {
180+
comparatorToUse = ((DefaultListableBeanFactory) beanFactory).getDependencyComparator();
181+
}
182+
if (comparatorToUse == null) {
183+
comparatorToUse = OrderComparator.INSTANCE;
184+
}
185+
translators.sort(comparatorToUse);
186+
}
187+
170188
ChainedPersistenceExceptionTranslator cpet = new ChainedPersistenceExceptionTranslator();
171-
for (PersistenceExceptionTranslator pet : pets.values()) {
189+
for (PersistenceExceptionTranslator pet : translators) {
172190
cpet.addDelegate(pet);
173191
}
174192
return cpet;

spring-tx/src/test/java/org/springframework/dao/annotation/PersistenceExceptionTranslationInterceptorTests.java

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2007 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,19 +16,34 @@
1616

1717
package org.springframework.dao.annotation;
1818

19+
import java.util.ArrayList;
20+
import java.util.List;
21+
22+
import org.aopalliance.intercept.MethodInvocation;
23+
import org.junit.jupiter.api.Test;
24+
1925
import org.springframework.aop.framework.ProxyFactory;
2026
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
2127
import org.springframework.beans.factory.support.RootBeanDefinition;
28+
import org.springframework.core.Ordered;
29+
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
2230
import org.springframework.core.annotation.AnnotationUtils;
31+
import org.springframework.dao.DataAccessException;
2332
import org.springframework.dao.support.PersistenceExceptionTranslationInterceptor;
2433
import org.springframework.dao.support.PersistenceExceptionTranslator;
2534
import org.springframework.stereotype.Repository;
2635

36+
import static org.assertj.core.api.Assertions.assertThat;
37+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
38+
import static org.mockito.BDDMockito.given;
39+
import static org.mockito.Mockito.mock;
40+
2741
/**
2842
* Tests for standalone usage of a PersistenceExceptionTranslationInterceptor, as explicit advice bean in a BeanFactory
2943
* rather than applied as part of a PersistenceExceptionTranslationAdvisor.
3044
*
3145
* @author Juergen Hoeller
46+
* @author Tadaya Tsuyukubo
3247
*/
3348
public class PersistenceExceptionTranslationInterceptorTests extends PersistenceExceptionTranslationAdvisorTests {
3449

@@ -42,4 +57,50 @@ protected void addPersistenceExceptionTranslation(ProxyFactory pf, PersistenceEx
4257
}
4358
}
4459

60+
@Test
61+
void detectPersistenceExceptionTranslators() throws Throwable {
62+
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
63+
bf.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
64+
bf.registerBeanDefinition("peti", new RootBeanDefinition(PersistenceExceptionTranslationInterceptor.class));
65+
66+
List<Integer> callOrder = new ArrayList<>();
67+
bf.registerSingleton("pet20", new CallOrderAwareExceptionTranslator(20, callOrder));
68+
bf.registerSingleton("pet10", new CallOrderAwareExceptionTranslator(10, callOrder));
69+
bf.registerSingleton("pet30", new CallOrderAwareExceptionTranslator(30, callOrder));
70+
71+
PersistenceExceptionTranslationInterceptor interceptor = bf.getBean("peti", PersistenceExceptionTranslationInterceptor.class);
72+
interceptor.setAlwaysTranslate(true);
73+
74+
RuntimeException exception = new RuntimeException();
75+
MethodInvocation invocation = mock(MethodInvocation.class);
76+
given(invocation.proceed()).willThrow(exception);
77+
78+
assertThatThrownBy(() -> interceptor.invoke(invocation)).isSameAs(exception);
79+
80+
assertThat(callOrder).containsExactly(10, 20, 30);
81+
}
82+
83+
private static class CallOrderAwareExceptionTranslator implements PersistenceExceptionTranslator, Ordered {
84+
85+
private final int order;
86+
87+
private final List<Integer> callOrder;
88+
89+
public CallOrderAwareExceptionTranslator(int order, List<Integer> callOrder) {
90+
this.order = order;
91+
this.callOrder = callOrder;
92+
}
93+
94+
@Override
95+
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
96+
callOrder.add(this.order);
97+
return null;
98+
}
99+
100+
@Override
101+
public int getOrder() {
102+
return this.order;
103+
}
104+
}
105+
45106
}

0 commit comments

Comments
 (0)