Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
import org.springframework.core.Ordered;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.ResolvableType;
import org.springframework.core.TailOrdered;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.annotation.Order;
import org.springframework.core.convert.support.DefaultConversionService;
Expand Down Expand Up @@ -1531,6 +1532,43 @@ void autowirePreferredConstructorFromAttribute() throws Exception {
assertThat(bean.getSpouse2()).isNull();
}

@Test
void ordering() {
GenericBeanDefinition bd1 = new GenericBeanDefinition();
bd1.setBeanClass(TestBean.class);
bd1.setPropertyValues(new MutablePropertyValues(List.of(new PropertyValue("name", "lowest"))));
bd1.setAttribute(AbstractBeanDefinition.ORDER_ATTRIBUTE, Ordered.LOWEST_PRECEDENCE);
lbf.registerBeanDefinition("bean1", bd1);
GenericBeanDefinition bd2 = new GenericBeanDefinition();
bd2.setBeanClass(DerivedTestBean.class);
bd2.setPropertyValues(new MutablePropertyValues(List.of(new PropertyValue("name", "highest"))));
bd2.setAttribute(AbstractBeanDefinition.ORDER_ATTRIBUTE, Ordered.HIGHEST_PRECEDENCE);
bd2.setScope(BeanDefinition.SCOPE_PROTOTYPE);
lbf.registerBeanDefinition("bean2", bd2);
GenericBeanDefinition bd3 = new GenericBeanDefinition();
bd3.setBeanClass(HighestTailPrecedenceTestBean.class);
bd3.setPropertyValues(new MutablePropertyValues(List.of(new PropertyValue("name", "highestTail"))));
lbf.registerBeanDefinition("bean3", bd3);
GenericBeanDefinition bd4 = new GenericBeanDefinition();
bd4.setBeanClass(LowestTailPrecedenceTestBean.class);
bd4.setPropertyValues(new MutablePropertyValues(List.of(new PropertyValue("name", "lowestTail"))));
lbf.registerBeanDefinition("bean4", bd4);

assertThat(lbf.getBeanProvider(TestBean.class).orderedStream().map(TestBean::getName))
.containsExactly("highest", "lowest", "highestTail", "lowestTail");
assertThat(lbf.getBeanProvider(TestBean.class).orderedStream(clazz -> !DerivedTestBean.class.isAssignableFrom(clazz))
.map(TestBean::getName)).containsExactly("lowest", "highestTail", "lowestTail");
assertThat(lbf.getBeanProvider(TestBean.class).orderedStream(ObjectProvider.UNFILTERED).map(TestBean::getName))
.containsExactly("highest", "lowest", "highestTail", "lowestTail");
assertThat(lbf.getBeanProvider(TestBean.class).orderedStream(ObjectProvider.UNFILTERED, false).map(TestBean::getName))
.containsExactly("lowest", "highestTail", "lowestTail");

assertThat(lbf.getOrder("bean1")).isEqualTo(Ordered.LOWEST_PRECEDENCE);
assertThat(lbf.getOrder("bean2")).isEqualTo(Ordered.HIGHEST_PRECEDENCE);
assertThat(lbf.getOrder("bean3")).isEqualTo(Ordered.HIGHEST_PRECEDENCE);
assertThat(lbf.getOrder("bean4")).isEqualTo(Ordered.LOWEST_PRECEDENCE);
}

@Test
void orderFromAttribute() {
GenericBeanDefinition bd1 = new GenericBeanDefinition();
Expand Down Expand Up @@ -3896,6 +3934,24 @@ public Class<?> getObjectType() {
}
}


private static class LowestTailPrecedenceTestBean extends TestBean implements TailOrdered {

@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
}


private static class HighestTailPrecedenceTestBean extends TestBean implements TailOrdered {

@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
}

private static class Template<T> {

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
*
* @author Juergen Hoeller
* @author Sam Brannen
* @author Yanming Zhou
* @since 07.04.2003
* @see Ordered
* @see PriorityOrdered
Expand Down Expand Up @@ -84,6 +85,15 @@ else if (p2 && !p1) {
return 1;
}

boolean t1 = (o1 instanceof TailOrdered);
boolean t2 = (o2 instanceof TailOrdered);
if (t1 && !t2) {
return 1;
}
else if (t2 && !t1) {
return -1;
}

int i1 = getOrder(o1, sourceProvider);
int i2 = getOrder(o2, sourceProvider);
return Integer.compare(i1, i2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
* @author Juergen Hoeller
* @author Sam Brannen
* @since 2.5
* @see TailOrdered
* @see org.springframework.beans.factory.config.PropertyOverrideConfigurer
*/
public interface PriorityOrdered extends Ordered {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright 2002-present 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
*
* https://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.core;

/**
* Extension of the {@link Ordered} interface, expressing a <em>tail</em>
* ordering: {@code TailOrdered} objects are always applied after
* <em>plain</em> {@link Ordered} objects regardless of their order values.
*
* <p>When sorting a set of {@code Ordered} objects, {@code TailOrdered}
* objects and <em>plain</em> {@code Ordered} objects are effectively treated as
* two separate subsets, with the set of {@code TailOrdered} objects following
* the set of <em>plain</em> {@code Ordered} objects and with relative
* ordering applied within those subsets.
*
* @author Yanming Zhou
* @since 7.1
* @see PriorityOrdered
*/
public interface TailOrdered extends Ordered {
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
* @author Stephane Nicoll
* @author Juergen Hoeller
* @author Sam Brannen
* @author Yanming Zhou
*/
class OrderComparatorTests {

Expand Down Expand Up @@ -105,6 +106,61 @@ private void assertThatPriorityOrderedAlwaysWins(StubPriorityOrdered priority, S
assertThat(this.comparator.compare(standard, priority)).isEqualTo(1);
}

@Test
void compareTailOrderedInstancesBefore() {
assertThat(this.comparator.compare(new StubTailOrdered(100), new StubTailOrdered(2000))).isEqualTo(-1);
}

@Test
void compareTailOrderedInstancesSame() {
assertThat(this.comparator.compare(new StubTailOrdered(100), new StubTailOrdered(100))).isEqualTo(0);
}

@Test
void compareTailOrderedInstancesAfter() {
assertThat(this.comparator.compare(new StubTailOrdered(982300), new StubTailOrdered(100))).isEqualTo(1);
}

@Test
void compareTailOrderedInstanceToStandardOrderedInstanceWithHigherPriority() {
assertThatTailOrderedAlwaysLoses(new StubTailOrdered(200), new StubOrdered(100));
}

@Test
void compareTailOrderedInstanceToStandardOrderedInstanceWithSamePriority() {
assertThatTailOrderedAlwaysLoses(new StubTailOrdered(100), new StubOrdered(100));
}

@Test
void compareTailOrderedInstanceToStandardOrderedInstanceWithLowerPriority() {
assertThatTailOrderedAlwaysLoses(new StubTailOrdered(100), new StubOrdered(200));
}

private void assertThatTailOrderedAlwaysLoses(StubTailOrdered priority, StubOrdered standard) {
assertThat(this.comparator.compare(priority, standard)).isEqualTo(1);
assertThat(this.comparator.compare(standard, priority)).isEqualTo(-1);
}

@Test
void compareTailOrderedInstanceToPriorityOrderedInstanceWithHigherPriority() {
assertThatTailOrderedAlwaysLoses(new StubTailOrdered(200), new StubPriorityOrdered(100));
}

@Test
void compareTailOrderedInstanceToPriorityOrderedInstanceWithSamePriority() {
assertThatTailOrderedAlwaysLoses(new StubTailOrdered(100), new StubPriorityOrdered(100));
}

@Test
void compareTailOrderedInstanceToPriorityOrderedInstanceWithLowerPriority() {
assertThatTailOrderedAlwaysLoses(new StubTailOrdered(100), new StubPriorityOrdered(200));
}

private void assertThatTailOrderedAlwaysLoses(StubTailOrdered priority, StubPriorityOrdered standard) {
assertThat(this.comparator.compare(priority, standard)).isEqualTo(1);
assertThat(this.comparator.compare(standard, priority)).isEqualTo(-1);
}

@Test
void compareWithSimpleSourceProvider() {
Comparator<Object> customComparator = this.comparator.withSourceProvider(
Expand Down Expand Up @@ -162,6 +218,20 @@ public int getOrder() {
}
}

private static class StubTailOrdered implements TailOrdered {

private final int order;

StubTailOrdered(int order) {
this.order = order;
}

@Override
public int getOrder() {
return this.order;
}
}

private static class TestSourceProvider implements OrderComparator.OrderSourceProvider {

private final Object target;
Expand Down