Skip to content

Commit 9539920

Browse files
committed
Map injection should honor the sorting order
Fix spring-projectsGH-34688 Signed-off-by: Yanming Zhou <zhouyanming@gmail.com>
1 parent 533283a commit 9539920

File tree

2 files changed

+43
-0
lines changed

2 files changed

+43
-0
lines changed

spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@
119119
* @author Phillip Webb
120120
* @author Stephane Nicoll
121121
* @author Sebastien Deleuze
122+
* @author Yanming Zhou
122123
* @since 16 April 2001
123124
* @see #registerBeanDefinition
124125
* @see #addBeanPostProcessor
@@ -1806,6 +1807,10 @@ else if (Map.class.isAssignableFrom(type) && type.isInterface()) {
18061807
if (autowiredBeanNames != null) {
18071808
autowiredBeanNames.addAll(matchingBeans.keySet());
18081809
}
1810+
Comparator<Object> comparator = adaptDependencyComparator(matchingBeans);
1811+
if (comparator != null) {
1812+
matchingBeans = sortMatchingBeans(matchingBeans, comparator);
1813+
}
18091814
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
18101815
return converter.convertIfNecessary(matchingBeans, descriptor.getDependencyType());
18111816
}
@@ -1819,6 +1824,16 @@ private boolean isRequired(DependencyDescriptor descriptor) {
18191824
return getAutowireCandidateResolver().isRequired(descriptor);
18201825
}
18211826

1827+
private <T> Map<String, T> sortMatchingBeans(Map<String, T> matchingBeans, Comparator<Object> comparator) {
1828+
List<Map.Entry<String, T>> list = new ArrayList<>(matchingBeans.entrySet());
1829+
list.sort(Map.Entry.comparingByValue(comparator));
1830+
Map<String, T> result = CollectionUtils.newLinkedHashMap(list.size());
1831+
for(Map.Entry<String, T> entry : list) {
1832+
result.put(entry.getKey(), entry.getValue());
1833+
}
1834+
return result;
1835+
}
1836+
18221837
private @Nullable Comparator<Object> adaptDependencyComparator(Map<String, ?> matchingBeans) {
18231838
Comparator<Object> comparator = getDependencyComparator();
18241839
if (comparator instanceof OrderComparator orderComparator) {

spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
import org.springframework.beans.factory.config.BeanDefinition;
6363
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
6464
import org.springframework.beans.factory.config.TypedStringValue;
65+
import org.springframework.beans.factory.support.AbstractBeanDefinition;
6566
import org.springframework.beans.factory.support.AutowireCandidateQualifier;
6667
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
6768
import org.springframework.beans.factory.support.GenericBeanDefinition;
@@ -93,6 +94,7 @@
9394
* @author Sam Brannen
9495
* @author Chris Beams
9596
* @author Stephane Nicoll
97+
* @author Yanming Zhou
9698
*/
9799
class AutowiredAnnotationBeanPostProcessorTests {
98100

@@ -1297,6 +1299,32 @@ void methodInjectionWithMap() {
12971299
assertThat(bean.getTestBean()).isSameAs(tb);
12981300
}
12991301

1302+
@Test
1303+
void mapInjectionShouldHonorTheSortingOrder() {
1304+
RootBeanDefinition bd = new RootBeanDefinition(MapMethodInjectionBean.class);
1305+
bf.registerBeanDefinition("annotatedBean", bd);
1306+
RootBeanDefinition bd1 = new RootBeanDefinition();
1307+
bd1.setBeanClass(TestBean.class);
1308+
bd1.setAttribute(AbstractBeanDefinition.ORDER_ATTRIBUTE, Ordered.LOWEST_PRECEDENCE);
1309+
bf.registerBeanDefinition("bean1", bd1);
1310+
RootBeanDefinition bd2 = new RootBeanDefinition();
1311+
bd2.setBeanClass(DerivedTestBean.class);
1312+
bd2.setAttribute(AbstractBeanDefinition.ORDER_ATTRIBUTE, Ordered.HIGHEST_PRECEDENCE);
1313+
bd2.setPrimary(true);
1314+
bf.registerBeanDefinition("bean2", bd2);
1315+
RootBeanDefinition bd3 = new RootBeanDefinition();
1316+
bd3.setBeanClass(TestBean.class);
1317+
bd3.setAttribute(AbstractBeanDefinition.ORDER_ATTRIBUTE, Ordered.HIGHEST_PRECEDENCE + 1);
1318+
bf.registerBeanDefinition("bean3", bd3);
1319+
RootBeanDefinition bd4 = new RootBeanDefinition();
1320+
bd4.setBeanClass(TestBean.class);
1321+
bd4.setAttribute(AbstractBeanDefinition.ORDER_ATTRIBUTE, Ordered.LOWEST_PRECEDENCE - 1);
1322+
bf.registerBeanDefinition("bean4", bd4);
1323+
1324+
MapMethodInjectionBean bean = bf.getBean("annotatedBean", MapMethodInjectionBean.class);
1325+
assertThat(bean.getTestBeanMap().keySet()).containsExactly("bean2", "bean3", "bean4", "bean1");
1326+
}
1327+
13001328
@Test
13011329
void methodInjectionWithMapAndMultipleMatches() {
13021330
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(MapMethodInjectionBean.class));

0 commit comments

Comments
 (0)