diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java index 3052a398e55a2f65c41c26a97f90eb6fa2e20e60..62505f1e9c8139872b45b24992d132fd45452933 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java @@ -1459,14 +1459,27 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto @Override public Object getOrderSource(Object obj) { - return getFactoryMethod(this.instancesToBeanNames.get(obj)); + RootBeanDefinition beanDefinition = getRootBeanDefinition(this.instancesToBeanNames.get(obj)); + if (beanDefinition == null) { + return null; + } + List sources = new ArrayList(); + Method factoryMethod = beanDefinition.getResolvedFactoryMethod(); + if (factoryMethod != null) { + sources.add(factoryMethod); + } + Class targetType = beanDefinition.getTargetType(); + if (targetType != null && !targetType.equals(obj.getClass())) { + sources.add(targetType); + } + return sources.toArray(new Object[sources.size()]); } - private Method getFactoryMethod(String beanName) { + private RootBeanDefinition getRootBeanDefinition(String beanName) { if (beanName != null && containsBeanDefinition(beanName)) { BeanDefinition bd = getMergedBeanDefinition(beanName); if (bd instanceof RootBeanDefinition) { - return ((RootBeanDefinition) bd).getResolvedFactoryMethod(); + return (RootBeanDefinition) bd; } } return null; diff --git a/spring-context/src/test/java/org/springframework/context/annotation/Spr12636Tests.java b/spring-context/src/test/java/org/springframework/context/annotation/Spr12636Tests.java new file mode 100644 index 0000000000000000000000000000000000000000..e4e9134effdeb09afae70156fcaed982901077ba --- /dev/null +++ b/spring-context/src/test/java/org/springframework/context/annotation/Spr12636Tests.java @@ -0,0 +1,117 @@ +/* + * Copyright 2002-2015 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +import java.util.List; + +import org.junit.After; +import org.junit.Test; + +import org.springframework.aop.support.AopUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.annotation.Order; +import org.springframework.scheduling.annotation.Async; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.stereotype.Component; + +import static org.junit.Assert.*; + +/** + * @author Stephane Nicoll + */ +public class Spr12636Tests { + + private ConfigurableApplicationContext context; + + @After + public void closeContext() { + if (this.context != null) { + this.context.close(); + } + } + + @Test + public void orderOnImplementation() { + this.context = new AnnotationConfigApplicationContext( + UserServiceTwo.class, UserServiceOne.class, UserServiceCollector.class); + UserServiceCollector bean = this.context.getBean(UserServiceCollector.class); + assertSame(context.getBean("serviceOne", UserService.class), bean.userServices.get(0)); + assertSame(context.getBean("serviceTwo", UserService.class), bean.userServices.get(1)); + + } + + @Test + public void orderOnImplementationWithProxy() { + this.context = new AnnotationConfigApplicationContext( + UserServiceTwo.class, UserServiceOne.class, UserServiceCollector.class, AsyncConfig.class); + + // Validate those beans are indeed wrapped by a proxy + UserService serviceOne = this.context.getBean("serviceOne", UserService.class); + UserService serviceTwo = this.context.getBean("serviceTwo", UserService.class); + assertTrue(AopUtils.isAopProxy(serviceOne)); + assertTrue(AopUtils.isAopProxy(serviceTwo)); + + UserServiceCollector bean = this.context.getBean(UserServiceCollector.class); + assertSame(serviceOne, bean.userServices.get(0)); + assertSame(serviceTwo, bean.userServices.get(1)); + } + + @Configuration + @EnableAsync + static class AsyncConfig { + } + + + @Component + static class UserServiceCollector { + + public final List userServices; + + @Autowired + UserServiceCollector(List userServices) { + this.userServices = userServices; + } + } + + interface UserService { + + void doIt(); + } + + @Component("serviceOne") + @Order(1) + static class UserServiceOne implements UserService { + + @Async + @Override + public void doIt() { + + } + } + + @Component("serviceTwo") + @Order(2) + static class UserServiceTwo implements UserService { + + @Async + @Override + public void doIt() { + + } + } +} diff --git a/spring-core/src/main/java/org/springframework/core/OrderComparator.java b/spring-core/src/main/java/org/springframework/core/OrderComparator.java index f4f81d3c8c40f24d2e0effa6bf7fc4aa482b1079..2a9970b9d9c97ed2d578349b005f656c60444212 100644 --- a/spring-core/src/main/java/org/springframework/core/OrderComparator.java +++ b/spring-core/src/main/java/org/springframework/core/OrderComparator.java @@ -21,6 +21,8 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; +import org.springframework.util.ObjectUtils; + /** * {@link Comparator} implementation for {@link Ordered} objects, * sorting by order value ascending (resp. by priority descending). @@ -89,7 +91,19 @@ public class OrderComparator implements Comparator { private int getOrder(Object obj, OrderSourceProvider sourceProvider) { Integer order = null; if (sourceProvider != null) { - order = findOrder(sourceProvider.getOrderSource(obj)); + Object orderSource = sourceProvider.getOrderSource(obj); + if (orderSource != null && orderSource.getClass().isArray()) { + Object[] sources = ObjectUtils.toObjectArray(orderSource); + for (Object source : sources) { + order = findOrder(source); + if (order != null) { + break; + } + } + } + else { + order = findOrder(orderSource); + } } return (order != null ? order : getOrder(obj)); } @@ -186,6 +200,7 @@ public class OrderComparator implements Comparator { /** * Return an order source for the specified object, i.e. an object that * should be checked for an order value as a replacement to the given object. + *

Can also be an array of order source objects. *

If the returned object does not indicate any order, the comparator * will fall back to checking the original object. * @param obj the object to find an order source for diff --git a/spring-core/src/test/java/org/springframework/core/OrderComparatorTests.java b/spring-core/src/test/java/org/springframework/core/OrderComparatorTests.java index 19e96f21c5f818cb653d83e5bf2003e9e786389a..30c221681ad174b1aee8dda67b326093deca090f 100644 --- a/spring-core/src/test/java/org/springframework/core/OrderComparatorTests.java +++ b/spring-core/src/test/java/org/springframework/core/OrderComparatorTests.java @@ -18,43 +18,90 @@ package org.springframework.core; import java.util.Comparator; -import junit.framework.TestCase; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; /** * Unit tests for the {@link OrderComparator} class. * * @author Rick Evans + * @author Stephane Nicoll */ -public final class OrderComparatorTests extends TestCase { - - private Comparator comparator; - - - @Override - protected void setUp() throws Exception { - this.comparator = new OrderComparator(); - } +public final class OrderComparatorTests { + private final OrderComparator comparator = new OrderComparator(); - public void testCompareOrderedInstancesBefore() throws Exception { + @Test + public void compareOrderedInstancesBefore() { assertEquals(-1, this.comparator.compare( new StubOrdered(100), new StubOrdered(2000))); } - public void testCompareOrderedInstancesSame() throws Exception { + @Test + public void compareOrderedInstancesSame() { assertEquals(0, this.comparator.compare( new StubOrdered(100), new StubOrdered(100))); } - public void testCompareOrderedInstancesAfter() throws Exception { + @Test + public void compareOrderedInstancesAfter() { assertEquals(1, this.comparator.compare( new StubOrdered(982300), new StubOrdered(100))); } - public void testCompareTwoNonOrderedInstancesEndsUpAsSame() throws Exception { + @Test + public void compareTwoNonOrderedInstancesEndsUpAsSame() { assertEquals(0, this.comparator.compare(new Object(), new Object())); } + @Test + public void compareWithSimpleSourceProvider() { + Comparator customComparator = this.comparator.withSourceProvider( + new TestSourceProvider(5L, new StubOrdered(25))); + assertEquals(-1, customComparator.compare(new StubOrdered(10), 5L)); + } + + @Test + public void compareWithSourceProviderArray() { + Comparator customComparator = this.comparator.withSourceProvider( + new TestSourceProvider(5L, new Object[] {new StubOrdered(10), new StubOrdered(-25)})); + assertEquals(-1, customComparator.compare(5L, new Object())); + } + + @Test + public void compareWithSourceProviderArrayNoMatch() { + Comparator customComparator = this.comparator.withSourceProvider( + new TestSourceProvider(5L, new Object[]{new Object(), new Object()})); + assertEquals(0, customComparator.compare(new Object(), 5L)); + } + + @Test + public void compareWithSourceProviderEmpty() { + Comparator customComparator = this.comparator.withSourceProvider( + new TestSourceProvider(50L, new Object())); + assertEquals(0, customComparator.compare(new Object(), 5L)); + } + + + private static final class TestSourceProvider implements OrderComparator.OrderSourceProvider { + + private final Object target; + private final Object orderSource; + + public TestSourceProvider(Object target, Object orderSource) { + this.target = target; + this.orderSource = orderSource; + } + + @Override + public Object getOrderSource(Object obj) { + if (target.equals(obj)) { + return orderSource; + } + return null; + } + } private static final class StubOrdered implements Ordered {