001/* 002 * Copyright 2002-2019 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.core.annotation; 018 019import java.lang.reflect.AnnotatedElement; 020import java.util.Map; 021 022import org.springframework.core.annotation.MergedAnnotations.SearchStrategy; 023import org.springframework.lang.Nullable; 024import org.springframework.util.ConcurrentReferenceHashMap; 025 026/** 027 * General utility for determining the order of an object based on its type declaration. 028 * Handles Spring's {@link Order} annotation as well as {@link javax.annotation.Priority}. 029 * 030 * @author Stephane Nicoll 031 * @author Juergen Hoeller 032 * @since 4.1 033 * @see Order 034 * @see javax.annotation.Priority 035 */ 036public abstract class OrderUtils { 037 038 /** Cache marker for a non-annotated Class. */ 039 private static final Object NOT_ANNOTATED = new Object(); 040 041 private static final String JAVAX_PRIORITY_ANNOTATION = "javax.annotation.Priority"; 042 043 /** Cache for @Order value (or NOT_ANNOTATED marker) per Class. */ 044 private static final Map<AnnotatedElement, Object> orderCache = new ConcurrentReferenceHashMap<>(64); 045 046 047 /** 048 * Return the order on the specified {@code type}, or the specified 049 * default value if none can be found. 050 * <p>Takes care of {@link Order @Order} and {@code @javax.annotation.Priority}. 051 * @param type the type to handle 052 * @return the priority value, or the specified default order if none can be found 053 * @since 5.0 054 * @see #getPriority(Class) 055 */ 056 public static int getOrder(Class<?> type, int defaultOrder) { 057 Integer order = getOrder(type); 058 return (order != null ? order : defaultOrder); 059 } 060 061 /** 062 * Return the order on the specified {@code type}, or the specified 063 * default value if none can be found. 064 * <p>Takes care of {@link Order @Order} and {@code @javax.annotation.Priority}. 065 * @param type the type to handle 066 * @return the priority value, or the specified default order if none can be found 067 * @see #getPriority(Class) 068 */ 069 @Nullable 070 public static Integer getOrder(Class<?> type, @Nullable Integer defaultOrder) { 071 Integer order = getOrder(type); 072 return (order != null ? order : defaultOrder); 073 } 074 075 /** 076 * Return the order on the specified {@code type}. 077 * <p>Takes care of {@link Order @Order} and {@code @javax.annotation.Priority}. 078 * @param type the type to handle 079 * @return the order value, or {@code null} if none can be found 080 * @see #getPriority(Class) 081 */ 082 @Nullable 083 public static Integer getOrder(Class<?> type) { 084 return getOrderFromAnnotations(type, MergedAnnotations.from(type, SearchStrategy.TYPE_HIERARCHY)); 085 } 086 087 /** 088 * Return the order from the specified annotations collection. 089 * <p>Takes care of {@link Order @Order} and 090 * {@code @javax.annotation.Priority}. 091 * @param element the source element 092 * @param annotations the annotation to consider 093 * @return the order value, or {@code null} if none can be found 094 */ 095 @Nullable 096 static Integer getOrderFromAnnotations(AnnotatedElement element, MergedAnnotations annotations) { 097 if (!(element instanceof Class)) { 098 return findOrder(annotations); 099 } 100 Object cached = orderCache.get(element); 101 if (cached != null) { 102 return (cached instanceof Integer ? (Integer) cached : null); 103 } 104 Integer result = findOrder(annotations); 105 orderCache.put(element, result != null ? result : NOT_ANNOTATED); 106 return result; 107 } 108 109 @Nullable 110 private static Integer findOrder(MergedAnnotations annotations) { 111 MergedAnnotation<Order> orderAnnotation = annotations.get(Order.class); 112 if (orderAnnotation.isPresent()) { 113 return orderAnnotation.getInt(MergedAnnotation.VALUE); 114 } 115 MergedAnnotation<?> priorityAnnotation = annotations.get(JAVAX_PRIORITY_ANNOTATION); 116 if (priorityAnnotation.isPresent()) { 117 return priorityAnnotation.getInt(MergedAnnotation.VALUE); 118 } 119 return null; 120 } 121 122 /** 123 * Return the value of the {@code javax.annotation.Priority} annotation 124 * declared on the specified type, or {@code null} if none. 125 * @param type the type to handle 126 * @return the priority value if the annotation is declared, or {@code null} if none 127 */ 128 @Nullable 129 public static Integer getPriority(Class<?> type) { 130 return MergedAnnotations.from(type, SearchStrategy.TYPE_HIERARCHY).get(JAVAX_PRIORITY_ANNOTATION) 131 .getValue(MergedAnnotation.VALUE, Integer.class).orElse(null); 132 } 133 134}