diff --git a/build.gradle b/build.gradle index 99b0d166ec1b94aa60aff2cdb80b2fd74de22a22..31872face7343dec338fec73673d1efdb3ee8005 100644 --- a/build.gradle +++ b/build.gradle @@ -92,7 +92,7 @@ configure(allprojects) { project -> ext.javadocLinks = [ "http://docs.oracle.com/javase/7/docs/api/", - "http://docs.oracle.com/javaee/6/api/", + "http://docs.oracle.com/javaee/7/api/", "http://docs.oracle.com/cd/E13222_01/wls/docs90/javadocs/", // CommonJ "http://pic.dhe.ibm.com/infocenter/wasinfo/v7r0/topic/com.ibm.websphere.javadoc.doc/web/apidocs/", "http://glassfish.java.net/nonav/docs/v3/api/", @@ -245,6 +245,7 @@ project("spring-core") { optional("org.aspectj:aspectjweaver:${aspectjVersion}") optional("net.sf.jopt-simple:jopt-simple:4.6") optional("log4j:log4j:1.2.17") + testCompile("org.apache.tomcat.embed:tomcat-embed-core:8.0.3") testCompile("xmlunit:xmlunit:1.5") testCompile("org.codehaus.woodstox:wstx-asl:3.2.7") { exclude group: "stax", module: "stax-api" diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/BeanFactoryAspectInstanceFactory.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/BeanFactoryAspectInstanceFactory.java index 15d4eee5f08c21e15e49b378c10b27ed751eb914..4ac2b0282cf6f8d2739237030e6e9a1680e4f649 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/BeanFactoryAspectInstanceFactory.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/BeanFactoryAspectInstanceFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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. @@ -19,8 +19,7 @@ package org.springframework.aop.aspectj.annotation; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.core.Ordered; -import org.springframework.core.annotation.AnnotationUtils; -import org.springframework.core.annotation.Order; +import org.springframework.core.annotation.OrderUtils; import org.springframework.util.ClassUtils; /** @@ -110,10 +109,7 @@ public class BeanFactoryAspectInstanceFactory implements MetadataAwareAspectInst if (Ordered.class.isAssignableFrom(type) && this.beanFactory.isSingleton(this.name)) { return ((Ordered) this.beanFactory.getBean(this.name)).getOrder(); } - Order order = AnnotationUtils.findAnnotation(type, Order.class); - if (order != null) { - return order.value(); - } + return OrderUtils.getOrder(type, Ordered.LOWEST_PRECEDENCE); } return Ordered.LOWEST_PRECEDENCE; } diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/SimpleMetadataAwareAspectInstanceFactory.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/SimpleMetadataAwareAspectInstanceFactory.java index cc8dbf92c41ba8ad15e66d8d87fed678290a5eac..5b8113e7239341f2a94822f662d2f78e81259ec6 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/SimpleMetadataAwareAspectInstanceFactory.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/SimpleMetadataAwareAspectInstanceFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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. @@ -18,8 +18,7 @@ package org.springframework.aop.aspectj.annotation; import org.springframework.aop.aspectj.SimpleAspectInstanceFactory; import org.springframework.core.Ordered; -import org.springframework.core.annotation.AnnotationUtils; -import org.springframework.core.annotation.Order; +import org.springframework.core.annotation.OrderUtils; /** * Implementation of {@link MetadataAwareAspectInstanceFactory} that @@ -51,20 +50,9 @@ public class SimpleMetadataAwareAspectInstanceFactory extends SimpleAspectInstan return this.metadata; } - /** - * Determine a fallback order for the case that the aspect instance - * does not express an instance-specific order through implementing - * the {@link org.springframework.core.Ordered} interface. - *

The default implementation simply returns {@code Ordered.LOWEST_PRECEDENCE}. - * @param aspectClass the aspect class - */ @Override protected int getOrderForAspectClass(Class aspectClass) { - Order order = AnnotationUtils.findAnnotation(aspectClass, Order.class); - if (order != null) { - return order.value(); - } - return Ordered.LOWEST_PRECEDENCE; + return OrderUtils.getOrder(aspectClass, Ordered.LOWEST_PRECEDENCE); } } diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/SingletonMetadataAwareAspectInstanceFactory.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/SingletonMetadataAwareAspectInstanceFactory.java index c2025fec6d9d241cba0a4e9cdea96b2bcb46235a..0f83e6c2f0880696504d5f2dc4b9af1cbfab8922 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/SingletonMetadataAwareAspectInstanceFactory.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/SingletonMetadataAwareAspectInstanceFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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. @@ -18,8 +18,7 @@ package org.springframework.aop.aspectj.annotation; import org.springframework.aop.aspectj.SingletonAspectInstanceFactory; import org.springframework.core.Ordered; -import org.springframework.core.annotation.AnnotationUtils; -import org.springframework.core.annotation.Order; +import org.springframework.core.annotation.OrderUtils; /** * Implementation of {@link MetadataAwareAspectInstanceFactory} that is backed @@ -53,19 +52,9 @@ public class SingletonMetadataAwareAspectInstanceFactory extends SingletonAspect return this.metadata; } - /** - * Check whether the aspect class carries an - * {@link org.springframework.core.annotation.Order} annotation, - * falling back to {@code Ordered.LOWEST_PRECEDENCE}. - * @see org.springframework.core.annotation.Order - */ @Override protected int getOrderForAspectClass(Class aspectClass) { - Order order = AnnotationUtils.findAnnotation(aspectClass, Order.class); - if (order != null) { - return order.value(); - } - return Ordered.LOWEST_PRECEDENCE; + return OrderUtils.getOrder(aspectClass, Ordered.LOWEST_PRECEDENCE); } } 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 8249cd3399414916418ccbc4c95a5ddc1487784c..ca09ba071b379bab05ba3d41767d713d82aaddf0 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 @@ -60,6 +60,7 @@ import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.config.DependencyDescriptor; import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.core.annotation.OrderUtils; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; @@ -1156,12 +1157,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto * @return the priority assigned to that bean or {@code null} if none is set */ protected Integer getPriority(Object beanInstance) { - for (Annotation annotation : beanInstance.getClass().getAnnotations()) { - if ("javax.annotation.Priority".equals(annotation.annotationType().getName())) { - return (Integer) AnnotationUtils.getValue(annotation); - } - } - return null; + return OrderUtils.getPriorityValue(beanInstance.getClass()); } /** diff --git a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationAwareOrderComparator.java b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationAwareOrderComparator.java index f4a83b8f982b3b42af915d0170152e5423bf8691..760bdf5119dae1e65df130e9aaf2c8f47cff182c 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationAwareOrderComparator.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationAwareOrderComparator.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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. @@ -32,6 +32,7 @@ import org.springframework.core.Ordered; * * @author Juergen Hoeller * @author Oliver Gierke + * @author Stephane Nicoll * @since 2.0.1 * @see org.springframework.core.Ordered * @see Order @@ -51,10 +52,7 @@ public class AnnotationAwareOrderComparator extends OrderComparator { } if (obj != null) { Class clazz = (obj instanceof Class ? (Class) obj : obj.getClass()); - Order order = AnnotationUtils.findAnnotation(clazz, Order.class); - if (order != null) { - return order.value(); - } + return OrderUtils.getOrder(clazz, Ordered.LOWEST_PRECEDENCE); } return Ordered.LOWEST_PRECEDENCE; } diff --git a/spring-core/src/main/java/org/springframework/core/annotation/Order.java b/spring-core/src/main/java/org/springframework/core/annotation/Order.java index 54f81677dbb045dcfe09abc5ef384fed0f30d1fe..c88b49ca4443b042988697e65fc9793446a532b2 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/Order.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/Order.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2014 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. @@ -29,6 +29,9 @@ import org.springframework.core.Ordered; * The default value is {@code Ordered.LOWEST_PRECEDENCE}, indicating * lowest priority (losing to any other specified order value). * + *

Since Spring 4.1, the standard {@link javax.annotation.Priority} can be used as + * a drop-in replacement of this annotation. + * *

NOTE: Annotation-based ordering is supported for specific kinds of * components only, e.g. for annotation-based AspectJ aspects. Spring container * strategies, on the other hand, are typically based on the {@link Ordered} @@ -39,6 +42,8 @@ import org.springframework.core.Ordered; * @since 2.0 * @see org.springframework.core.Ordered * @see AnnotationAwareOrderComparator + * @see OrderUtils + * @see javax.annotation.Priority */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) diff --git a/spring-core/src/main/java/org/springframework/core/annotation/OrderUtils.java b/spring-core/src/main/java/org/springframework/core/annotation/OrderUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..202b0147762a4e64231d851fe19d886b03436960 --- /dev/null +++ b/spring-core/src/main/java/org/springframework/core/annotation/OrderUtils.java @@ -0,0 +1,75 @@ +/* + * Copyright 2002-2014 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.core.annotation; + +import java.lang.annotation.Annotation; + +import org.springframework.util.ClassUtils; + +/** + * General utility for determining the order of an object based + * on its type declaration. + * + * @author Stephane Nicoll + * @since 4.1 + * @see Order + * @see javax.annotation.Priority + */ +public abstract class OrderUtils { + + private static final String PRIORITY_ANNOTATION_CLASS_NAME = "javax.annotation.Priority"; + + private static final boolean priorityPresent = + ClassUtils.isPresent(PRIORITY_ANNOTATION_CLASS_NAME, OrderUtils.class.getClassLoader()); + + /** + * Return the order on the specified {@code type} or the specified + * default value if none can be found. + *

Take care of {@link Order @Order} and {@code @javax.annotation.Priority}. + * @param type the type to handle + * @return the priority value of the default if none can be found + */ + public static Integer getOrder(Class type, Integer defaultOrder) { + Order order = AnnotationUtils.findAnnotation(type, Order.class); + if (order != null) { + return order.value(); + } + Integer priorityOrder = getPriorityValue(type); + if (priorityOrder != null) { + return priorityOrder; + } + return defaultOrder; + } + + /** + * Return the value of the {@code javax.annotation.Priority} annotation set on the + * specified type or {@code null} if none is set. + * @param type the type to handle + * @return the priority value if the annotation is set, {@code null} otherwise + */ + public static Integer getPriorityValue(Class type) { + if (priorityPresent) { + for (Annotation annotation : type.getAnnotations()) { + if (PRIORITY_ANNOTATION_CLASS_NAME.equals(annotation.annotationType().getName())) { + return (Integer) AnnotationUtils.getValue(annotation); + } + } + } + return null; + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/annotation/AnnotationAwareOrderComparatorTests.java b/spring-core/src/test/java/org/springframework/core/annotation/AnnotationAwareOrderComparatorTests.java index df65665564d42c11c3f21c7320d023b6e96764d7..f6424a8f800ee8d8de1a897d9380fa99d06257c6 100644 --- a/spring-core/src/test/java/org/springframework/core/annotation/AnnotationAwareOrderComparatorTests.java +++ b/spring-core/src/test/java/org/springframework/core/annotation/AnnotationAwareOrderComparatorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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. @@ -24,6 +24,8 @@ import org.junit.Test; import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; +import javax.annotation.Priority; + /** * @author Juergen Hoeller * @author Oliver Gierke @@ -45,6 +47,26 @@ public class AnnotationAwareOrderComparatorTests { assertTrue(list.get(1) instanceof B); } + @Test + public void sortInstancesWithPriority() { + List list = new ArrayList<>(); + list.add(new B2()); + list.add(new A2()); + AnnotationAwareOrderComparator.sort(list); + assertTrue(list.get(0) instanceof A2); + assertTrue(list.get(1) instanceof B2); + } + + @Test + public void sortInstancesWithOrderAndPriority() { + List list = new ArrayList<>(); + list.add(new B()); + list.add(new A2()); + AnnotationAwareOrderComparator.sort(list); + assertTrue(list.get(0) instanceof A2); + assertTrue(list.get(1) instanceof B); + } + @Test public void sortInstancesWithSubclass() { List list = new ArrayList<>(); @@ -87,4 +109,12 @@ public class AnnotationAwareOrderComparatorTests { private static class C extends A { } + @Priority(1) + private static class A2 { + } + + @Priority(2) + private static class B2 { + } + } diff --git a/spring-core/src/test/java/org/springframework/core/annotation/OrderUtilsTests.java b/spring-core/src/test/java/org/springframework/core/annotation/OrderUtilsTests.java new file mode 100644 index 0000000000000000000000000000000000000000..c4968db59cdeb645e59032c1983d9bf7c0193c96 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/annotation/OrderUtilsTests.java @@ -0,0 +1,73 @@ +/* + * Copyright 2002-2014 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.core.annotation; + +import static org.junit.Assert.*; + +import javax.annotation.Priority; + +import org.junit.Test; + +/** + * + * @author Stephane Nicoll + */ +public class OrderUtilsTests { + + @Test + public void getSimpleOrder() { + assertEquals(Integer.valueOf(50), OrderUtils.getOrder(SimpleOrder.class, null)); + } + + @Test + public void getPriorityOrder() { + assertEquals(Integer.valueOf(55), OrderUtils.getOrder(SimplePriority.class, null)); + } + + @Test + public void getOrderWithBoth() { + assertEquals(Integer.valueOf(50), OrderUtils.getOrder(OrderAndPriority.class, null)); + } + + @Test + public void getDefaultOrder() { + assertEquals(Integer.valueOf(33), OrderUtils.getOrder(NoOrder.class, 33)); + } + + @Test + public void getPriorityValueNoAnnotation() { + assertNull(OrderUtils.getPriorityValue(SimpleOrder.class)); + } + + @Test + public void getPriorityValue() { + assertEquals(Integer.valueOf(55), OrderUtils.getPriorityValue(OrderAndPriority.class)); + } + + @Order(50) + private static class SimpleOrder {} + + @Priority(55) + private static class SimplePriority {} + + @Order(50) + @Priority(55) + private static class OrderAndPriority {} + + private static class NoOrder {} + +} diff --git a/spring-web/src/main/java/org/springframework/web/method/ControllerAdviceBean.java b/spring-web/src/main/java/org/springframework/web/method/ControllerAdviceBean.java index 4c0c7234efca0028e5ed42870e2ad06f1a91a844..c0aa26eb127c5f43c4a7ea5331ddff4812b2721f 100644 --- a/spring-web/src/main/java/org/springframework/web/method/ControllerAdviceBean.java +++ b/spring-web/src/main/java/org/springframework/web/method/ControllerAdviceBean.java @@ -29,7 +29,7 @@ import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.context.ApplicationContext; import org.springframework.core.Ordered; import org.springframework.core.annotation.AnnotationUtils; -import org.springframework.core.annotation.Order; +import org.springframework.core.annotation.OrderUtils; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; @@ -215,8 +215,7 @@ public class ControllerAdviceBean implements Ordered { } private static int initOrderFromBeanType(Class beanType) { - Order ann = AnnotationUtils.findAnnotation(beanType, Order.class); - return (ann != null ? ann.value() : Ordered.LOWEST_PRECEDENCE); + return OrderUtils.getOrder(beanType, Ordered.LOWEST_PRECEDENCE); } private static List initBasePackagesFromBeanType(Class beanType, ControllerAdvice annotation) { diff --git a/src/asciidoc/index.adoc b/src/asciidoc/index.adoc index 495a824387d217c79c7a18a8e1188f2a4830cf15..c1b3e476e9a5652c6469325f2aa65aa422965674 100644 --- a/src/asciidoc/index.adoc +++ b/src/asciidoc/index.adoc @@ -894,7 +894,7 @@ There have been several general improvements to the core container: * If you use Spring's meta-annotation support, you can now develop custom annotations that <>. * Beans can now be __ordered__ when they are <>. Both the `@Ordered` annotation and `Ordered` interface are + lists and arrays>>. Both the `@Order` annotation and `Ordered` interface are supported. * The `@Lazy` annotation can now be used on injection points, as well as on `@Bean` definitions. @@ -5147,9 +5147,9 @@ The same applies for typed collections: [TIP] ==== -Your beans can implement the `org.springframework.core.Ordered` interface or use the -the `@Ordered` annotation if you want items in the array or list to be sorted into a -specific order. +Your beans can implement the `org.springframework.core.Ordered` interface or either use +the `@Order` or standard `@Priority` annotation if you want items in the array or list +to be sorted into a specific order. ==== @@ -18867,8 +18867,8 @@ the concrete `ConfigurableApplicationContext` type supported by each declared initializer must be compatible with the type of `ApplicationContext` created by the `SmartContextLoader` in use (i.e., typically a `GenericApplicationContext`). Furthermore, the order in which the initializers are invoked depends on whether they -implement Spring's `Ordered` interface or are annotated with Spring's `@Order` -annotation. +implement Spring's `Ordered` interface, are annotated with Spring's `@Order` or the +standard `@Priority` annotation. [source,java,indent=0] [subs="verbatim,quotes"] @@ -18969,8 +18969,8 @@ override (i.e., replace) those defined in `BaseConfig`. In the following example that uses context initializers, the `ApplicationContext` for `ExtendedTest` will be initialized using `BaseInitializer` __and__ `ExtendedInitializer`. Note, however, that the order in which the initializers are -invoked depends on whether they implement Spring's `Ordered` interface or are annotated -with Spring's `@Order` annotation. +invoked depends on whether they implement Spring's `Ordered` interface, are annotated +with Spring's `@Order` or the standard `@Priority` annotation. [source,java,indent=0] [subs="verbatim,quotes"]