DefaultListableBeanFactory does not trigger early candidate creation ahead of primary bean selection

Issue: SPR-14611
(cherry picked from commit c4fcdb6)
This commit is contained in:
Juergen Hoeller 2016-08-24 22:56:47 +02:00
parent 74bf659c56
commit a7849b2861
4 changed files with 124 additions and 91 deletions

View File

@ -986,38 +986,47 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
return null; return null;
} }
@SuppressWarnings("unchecked")
private <T> NamedBeanHolder<T> resolveNamedBean(Class<T> requiredType, Object... args) throws BeansException { private <T> NamedBeanHolder<T> resolveNamedBean(Class<T> requiredType, Object... args) throws BeansException {
Assert.notNull(requiredType, "Required type must not be null"); Assert.notNull(requiredType, "Required type must not be null");
String[] beanNames = getBeanNamesForType(requiredType); String[] candidateNames = getBeanNamesForType(requiredType);
if (beanNames.length > 1) { if (candidateNames.length > 1) {
ArrayList<String> autowireCandidates = new ArrayList<String>(); List<String> autowireCandidates = new ArrayList<String>(candidateNames.length);
for (String beanName : beanNames) { for (String beanName : candidateNames) {
if (!containsBeanDefinition(beanName) || getBeanDefinition(beanName).isAutowireCandidate()) { if (!containsBeanDefinition(beanName) || getBeanDefinition(beanName).isAutowireCandidate()) {
autowireCandidates.add(beanName); autowireCandidates.add(beanName);
} }
} }
if (!autowireCandidates.isEmpty()) { if (!autowireCandidates.isEmpty()) {
beanNames = autowireCandidates.toArray(new String[autowireCandidates.size()]); candidateNames = autowireCandidates.toArray(new String[autowireCandidates.size()]);
} }
} }
if (beanNames.length == 1) { if (candidateNames.length == 1) {
String beanName = beanNames[0]; String beanName = candidateNames[0];
return new NamedBeanHolder<T>(beanName, getBean(beanName, requiredType, args)); return new NamedBeanHolder<T>(beanName, getBean(beanName, requiredType, args));
} }
else if (beanNames.length > 1) { else if (candidateNames.length > 1) {
Map<String, Object> candidates = new LinkedHashMap<String, Object>(); Map<String, Object> candidates = new LinkedHashMap<String, Object>(candidateNames.length);
for (String beanName : beanNames) { for (String candidateName : candidateNames) {
candidates.put(beanName, getBean(beanName, requiredType, args)); if (containsSingleton(candidateName)) {
candidates.put(candidateName, getBean(candidateName, requiredType, args));
}
else {
candidates.put(candidateName, getType(candidateName));
}
} }
String primaryCandidate = determinePrimaryCandidate(candidates, requiredType); String candidateName = determinePrimaryCandidate(candidates, requiredType);
if (primaryCandidate != null) { if (candidateName == null) {
return new NamedBeanHolder<T>(primaryCandidate, getBean(primaryCandidate, requiredType, args)); candidateName = determineHighestPriorityCandidate(candidates, requiredType);
} }
String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType); if (candidateName != null) {
if (priorityCandidate != null) { Object beanInstance = candidates.get(candidateName);
return new NamedBeanHolder<T>(priorityCandidate, getBean(priorityCandidate, requiredType, args)); if (beanInstance instanceof Class) {
beanInstance = getBean(candidateName, requiredType, args);
}
return new NamedBeanHolder<T>(candidateName, (T) beanInstance);
} }
throw new NoUniqueBeanDefinitionException(requiredType, candidates.keySet()); throw new NoUniqueBeanDefinitionException(requiredType, candidates.keySet());
} }
@ -1086,9 +1095,13 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
} }
return null; return null;
} }
String autowiredBeanName;
Object instanceCandidate;
if (matchingBeans.size() > 1) { if (matchingBeans.size() > 1) {
String primaryBeanName = determineAutowireCandidate(matchingBeans, descriptor); autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (primaryBeanName == null) { if (autowiredBeanName == null) {
if (descriptor.isRequired() || !indicatesMultipleBeans(type)) { if (descriptor.isRequired() || !indicatesMultipleBeans(type)) {
return descriptor.resolveNotUnique(type, matchingBeans); return descriptor.resolveNotUnique(type, matchingBeans);
} }
@ -1099,17 +1112,20 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
return null; return null;
} }
} }
if (autowiredBeanNames != null) { instanceCandidate = matchingBeans.get(autowiredBeanName);
autowiredBeanNames.add(primaryBeanName);
}
return matchingBeans.get(primaryBeanName);
} }
// We have exactly one match. else {
Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next(); // We have exactly one match.
Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
if (autowiredBeanNames != null) { if (autowiredBeanNames != null) {
autowiredBeanNames.add(entry.getKey()); autowiredBeanNames.add(autowiredBeanName);
} }
return entry.getValue(); return (instanceCandidate instanceof Class ?
descriptor.resolveCandidate(autowiredBeanName, type, this) : instanceCandidate);
} }
finally { finally {
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint); ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
@ -1122,9 +1138,8 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
Class<?> type = descriptor.getDependencyType(); Class<?> type = descriptor.getDependencyType();
if (type.isArray()) { if (type.isArray()) {
Class<?> componentType = type.getComponentType(); Class<?> componentType = type.getComponentType();
DependencyDescriptor targetDesc = new DependencyDescriptor(descriptor); Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType,
targetDesc.increaseNestingLevel(); new MultiElementDependencyDescriptor(descriptor));
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType, targetDesc);
if (matchingBeans.isEmpty()) { if (matchingBeans.isEmpty()) {
return null; return null;
} }
@ -1143,9 +1158,8 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
if (elementType == null) { if (elementType == null) {
return null; return null;
} }
DependencyDescriptor targetDesc = new DependencyDescriptor(descriptor); Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType,
targetDesc.increaseNestingLevel(); new MultiElementDependencyDescriptor(descriptor));
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType, targetDesc);
if (matchingBeans.isEmpty()) { if (matchingBeans.isEmpty()) {
return null; return null;
} }
@ -1168,9 +1182,8 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
if (valueType == null) { if (valueType == null) {
return null; return null;
} }
DependencyDescriptor targetDesc = new DependencyDescriptor(descriptor); Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType,
targetDesc.increaseNestingLevel(); new MultiElementDependencyDescriptor(descriptor));
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType, targetDesc);
if (matchingBeans.isEmpty()) { if (matchingBeans.isEmpty()) {
return null; return null;
} }
@ -1239,7 +1252,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
} }
for (String candidateName : candidateNames) { for (String candidateName : candidateNames) {
if (!isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, descriptor)) { if (!isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, descriptor)) {
result.put(candidateName, descriptor.resolveCandidate(candidateName, requiredType, this)); addCandidateEntry(result, candidateName, descriptor, requiredType);
} }
} }
if (result.isEmpty() && !indicatesMultipleBeans(requiredType)) { if (result.isEmpty() && !indicatesMultipleBeans(requiredType)) {
@ -1247,14 +1260,14 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch(); DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
for (String candidateName : candidateNames) { for (String candidateName : candidateNames) {
if (!isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, fallbackDescriptor)) { if (!isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, fallbackDescriptor)) {
result.put(candidateName, descriptor.resolveCandidate(candidateName, requiredType, this)); addCandidateEntry(result, candidateName, descriptor, requiredType);
} }
} }
if (result.isEmpty()) { if (result.isEmpty()) {
// Consider self references before as a final pass // Consider self references before as a final pass
for (String candidateName : candidateNames) { for (String candidateName : candidateNames) {
if (isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, fallbackDescriptor)) { if (isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, fallbackDescriptor)) {
result.put(candidateName, descriptor.resolveCandidate(candidateName, requiredType, this)); addCandidateEntry(result, candidateName, descriptor, requiredType);
} }
} }
} }
@ -1262,31 +1275,46 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
return result; return result;
} }
/**
* Add an entry to the candidate map: a bean instance if available or just the resolved
* type, preventing early bean initialization ahead of primary candidate selection.
*/
private void addCandidateEntry(Map<String, Object> candidates, String candidateName,
DependencyDescriptor descriptor, Class<?> requiredType) {
if (descriptor instanceof MultiElementDependencyDescriptor || containsSingleton(candidateName)) {
candidates.put(candidateName, descriptor.resolveCandidate(candidateName, requiredType, this));
}
else {
candidates.put(candidateName, getType(candidateName));
}
}
/** /**
* Determine the autowire candidate in the given set of beans. * Determine the autowire candidate in the given set of beans.
* <p>Looks for {@code @Primary} and {@code @Priority} (in that order). * <p>Looks for {@code @Primary} and {@code @Priority} (in that order).
* @param candidateBeans a Map of candidate names and candidate instances * @param candidates a Map of candidate names and candidate instances
* that match the required type, as returned by {@link #findAutowireCandidates} * that match the required type, as returned by {@link #findAutowireCandidates}
* @param descriptor the target dependency to match against * @param descriptor the target dependency to match against
* @return the name of the autowire candidate, or {@code null} if none found * @return the name of the autowire candidate, or {@code null} if none found
*/ */
protected String determineAutowireCandidate(Map<String, Object> candidateBeans, DependencyDescriptor descriptor) { protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) {
Class<?> requiredType = descriptor.getDependencyType(); Class<?> requiredType = descriptor.getDependencyType();
String primaryCandidate = determinePrimaryCandidate(candidateBeans, requiredType); String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
if (primaryCandidate != null) { if (primaryCandidate != null) {
return primaryCandidate; return primaryCandidate;
} }
String priorityCandidate = determineHighestPriorityCandidate(candidateBeans, requiredType); String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
if (priorityCandidate != null) { if (priorityCandidate != null) {
return priorityCandidate; return priorityCandidate;
} }
// Fallback // Fallback
for (Map.Entry<String, Object> entry : candidateBeans.entrySet()) { for (Map.Entry<String, Object> entry : candidates.entrySet()) {
String candidateBeanName = entry.getKey(); String candidateName = entry.getKey();
Object beanInstance = entry.getValue(); Object beanInstance = entry.getValue();
if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) || if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) ||
matchesBeanName(candidateBeanName, descriptor.getDependencyName())) { matchesBeanName(candidateName, descriptor.getDependencyName())) {
return candidateBeanName; return candidateName;
} }
} }
return null; return null;
@ -1294,15 +1322,15 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
/** /**
* Determine the primary candidate in the given set of beans. * Determine the primary candidate in the given set of beans.
* @param candidateBeans a Map of candidate names and candidate instances * @param candidates a Map of candidate names and candidate instances
* that match the required type * (or candidate classes if not created yet) that match the required type
* @param requiredType the target dependency type to match against * @param requiredType the target dependency type to match against
* @return the name of the primary candidate, or {@code null} if none found * @return the name of the primary candidate, or {@code null} if none found
* @see #isPrimary(String, Object) * @see #isPrimary(String, Object)
*/ */
protected String determinePrimaryCandidate(Map<String, Object> candidateBeans, Class<?> requiredType) { protected String determinePrimaryCandidate(Map<String, Object> candidates, Class<?> requiredType) {
String primaryBeanName = null; String primaryBeanName = null;
for (Map.Entry<String, Object> entry : candidateBeans.entrySet()) { for (Map.Entry<String, Object> entry : candidates.entrySet()) {
String candidateBeanName = entry.getKey(); String candidateBeanName = entry.getKey();
Object beanInstance = entry.getValue(); Object beanInstance = entry.getValue();
if (isPrimary(candidateBeanName, beanInstance)) { if (isPrimary(candidateBeanName, beanInstance)) {
@ -1310,8 +1338,8 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
boolean candidateLocal = containsBeanDefinition(candidateBeanName); boolean candidateLocal = containsBeanDefinition(candidateBeanName);
boolean primaryLocal = containsBeanDefinition(primaryBeanName); boolean primaryLocal = containsBeanDefinition(primaryBeanName);
if (candidateLocal && primaryLocal) { if (candidateLocal && primaryLocal) {
throw new NoUniqueBeanDefinitionException(requiredType, candidateBeans.size(), throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(),
"more than one 'primary' bean found among candidates: " + candidateBeans.keySet()); "more than one 'primary' bean found among candidates: " + candidates.keySet());
} }
else if (candidateLocal) { else if (candidateLocal) {
primaryBeanName = candidateBeanName; primaryBeanName = candidateBeanName;
@ -1326,29 +1354,30 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
} }
/** /**
* Determine the candidate with the highest priority in the given set of beans. As * Determine the candidate with the highest priority in the given set of beans.
* defined by the {@link org.springframework.core.Ordered} interface, the lowest * <p>Based on {@code @javax.annotation.Priority}. As defined by the related
* value has the highest priority. * {@link org.springframework.core.Ordered} interface, the lowest value has
* @param candidateBeans a Map of candidate names and candidate instances * the highest priority.
* that match the required type * @param candidates a Map of candidate names and candidate instances
* (or candidate classes if not created yet) that match the required type
* @param requiredType the target dependency type to match against * @param requiredType the target dependency type to match against
* @return the name of the candidate with the highest priority, * @return the name of the candidate with the highest priority,
* or {@code null} if none found * or {@code null} if none found
* @see #getPriority(Object) * @see #getPriority(Object)
*/ */
protected String determineHighestPriorityCandidate(Map<String, Object> candidateBeans, Class<?> requiredType) { protected String determineHighestPriorityCandidate(Map<String, Object> candidates, Class<?> requiredType) {
String highestPriorityBeanName = null; String highestPriorityBeanName = null;
Integer highestPriority = null; Integer highestPriority = null;
for (Map.Entry<String, Object> entry : candidateBeans.entrySet()) { for (Map.Entry<String, Object> entry : candidates.entrySet()) {
String candidateBeanName = entry.getKey(); String candidateBeanName = entry.getKey();
Object beanInstance = entry.getValue(); Object beanInstance = entry.getValue();
Integer candidatePriority = getPriority(beanInstance); Integer candidatePriority = getPriority(beanInstance);
if (candidatePriority != null) { if (candidatePriority != null) {
if (highestPriorityBeanName != null) { if (highestPriorityBeanName != null) {
if (candidatePriority.equals(highestPriority)) { if (candidatePriority.equals(highestPriority)) {
throw new NoUniqueBeanDefinitionException(requiredType, candidateBeans.size(), throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(),
"Multiple beans found with the same priority ('" + highestPriority + "') " + "Multiple beans found with the same priority ('" + highestPriority +
"among candidates: " + candidateBeans.keySet()); "') among candidates: " + candidates.keySet());
} }
else if (candidatePriority < highestPriority) { else if (candidatePriority < highestPriority) {
highestPriorityBeanName = candidateBeanName; highestPriorityBeanName = candidateBeanName;
@ -1529,7 +1558,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
private class OptionalDependencyFactory { private class OptionalDependencyFactory {
public Object createOptionalDependency(DependencyDescriptor descriptor, String beanName, final Object... args) { public Object createOptionalDependency(DependencyDescriptor descriptor, String beanName, final Object... args) {
DependencyDescriptor descriptorToUse = new DependencyDescriptor(descriptor) { DependencyDescriptor descriptorToUse = new NestedDependencyDescriptor(descriptor) {
@Override @Override
public boolean isRequired() { public boolean isRequired() {
return false; return false;
@ -1540,7 +1569,6 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
super.resolveCandidate(beanName, requiredType, beanFactory)); super.resolveCandidate(beanName, requiredType, beanFactory));
} }
}; };
descriptorToUse.increaseNestingLevel();
return Optional.ofNullable(doResolveDependency(descriptorToUse, beanName, null, null)); return Optional.ofNullable(doResolveDependency(descriptorToUse, beanName, null, null));
} }
} }
@ -1558,9 +1586,8 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
private final String beanName; private final String beanName;
public DependencyObjectProvider(DependencyDescriptor descriptor, String beanName) { public DependencyObjectProvider(DependencyDescriptor descriptor, String beanName) {
this.descriptor = new DependencyDescriptor(descriptor); this.descriptor = new NestedDependencyDescriptor(descriptor);
this.descriptor.increaseNestingLevel(); this.optional = (this.descriptor.getDependencyType() == javaUtilOptionalClass);
this.optional = this.descriptor.getDependencyType().equals(javaUtilOptionalClass);
this.beanName = beanName; this.beanName = beanName;
} }
@ -1676,7 +1703,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
if (beanDefinition == null) { if (beanDefinition == null) {
return null; return null;
} }
List<Object> sources = new ArrayList<Object>(); List<Object> sources = new ArrayList<Object>(2);
Method factoryMethod = beanDefinition.getResolvedFactoryMethod(); Method factoryMethod = beanDefinition.getResolvedFactoryMethod();
if (factoryMethod != null) { if (factoryMethod != null) {
sources.add(factoryMethod); sources.add(factoryMethod);
@ -1699,4 +1726,21 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
} }
} }
private static class NestedDependencyDescriptor extends DependencyDescriptor {
public NestedDependencyDescriptor(DependencyDescriptor original) {
super(original);
increaseNestingLevel();
}
}
private static class MultiElementDependencyDescriptor extends NestedDependencyDescriptor {
public MultiElementDependencyDescriptor(DependencyDescriptor original) {
super(original);
}
}
} }

View File

@ -1435,12 +1435,14 @@ public class DefaultListableBeanFactoryTests {
public void testGetBeanByTypeWithPrimary() throws Exception { public void testGetBeanByTypeWithPrimary() throws Exception {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
RootBeanDefinition bd1 = new RootBeanDefinition(TestBean.class); RootBeanDefinition bd1 = new RootBeanDefinition(TestBean.class);
bd1.setLazyInit(true);
RootBeanDefinition bd2 = new RootBeanDefinition(TestBean.class); RootBeanDefinition bd2 = new RootBeanDefinition(TestBean.class);
bd2.setPrimary(true); bd2.setPrimary(true);
lbf.registerBeanDefinition("bd1", bd1); lbf.registerBeanDefinition("bd1", bd1);
lbf.registerBeanDefinition("bd2", bd2); lbf.registerBeanDefinition("bd2", bd2);
TestBean bean = lbf.getBean(TestBean.class); TestBean bean = lbf.getBean(TestBean.class);
assertThat(bean.getBeanName(), equalTo("bd2")); assertThat(bean.getBeanName(), equalTo("bd2"));
assertFalse(lbf.containsSingleton("bd1"));
} }
@Test @Test
@ -1760,24 +1762,6 @@ public class DefaultListableBeanFactoryTests {
} }
} }
@Test
public void testAutowireBeanByTypeWithTwoMatchesAndParameterNameDiscovery() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class);
RootBeanDefinition bd2 = new RootBeanDefinition(TestBean.class);
lbf.registerBeanDefinition("test", bd);
lbf.registerBeanDefinition("spouse", bd2);
try {
lbf.autowire(DependenciesBean.class, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
fail("Should have thrown UnsatisfiedDependencyException");
}
catch (UnsatisfiedDependencyException ex) {
// expected
assertTrue(ex.getMessage().contains("test"));
assertTrue(ex.getMessage().contains("spouse"));
}
}
@Test @Test
public void testAutowireBeanByTypeWithDependencyCheck() { public void testAutowireBeanByTypeWithDependencyCheck() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();

View File

@ -1146,12 +1146,15 @@ public class AutowiredAnnotationBeanPostProcessorTests {
RootBeanDefinition tb1 = new RootBeanDefinition(TestBean.class); RootBeanDefinition tb1 = new RootBeanDefinition(TestBean.class);
tb1.setPrimary(true); tb1.setPrimary(true);
bf.registerBeanDefinition("testBean1", tb1); bf.registerBeanDefinition("testBean1", tb1);
bf.registerBeanDefinition("testBean2", new RootBeanDefinition(TestBean.class)); RootBeanDefinition tb2 = new RootBeanDefinition(TestBean.class);
tb2.setLazyInit(true);
bf.registerBeanDefinition("testBean2", tb2);
SmartObjectFactoryInjectionBean bean = (SmartObjectFactoryInjectionBean) bf.getBean("annotatedBean"); SmartObjectFactoryInjectionBean bean = (SmartObjectFactoryInjectionBean) bf.getBean("annotatedBean");
assertSame(bf.getBean("testBean1"), bean.getTestBean()); assertSame(bf.getBean("testBean1"), bean.getTestBean());
assertSame(bf.getBean("testBean1"), bean.getOptionalTestBean()); assertSame(bf.getBean("testBean1"), bean.getOptionalTestBean());
assertSame(bf.getBean("testBean1"), bean.getUniqueTestBean()); assertSame(bf.getBean("testBean1"), bean.getUniqueTestBean());
assertFalse(bf.containsSingleton("testBean2"));
bf.destroySingletons(); bf.destroySingletons();
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2014 the original author or authors. * Copyright 2002-2016 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -48,9 +48,10 @@ public abstract class OrderUtils {
/** /**
* Return the order on the specified {@code type}. * Return the order on the specified {@code type}.
* <p>Take care of {@link Order @Order} and {@code @javax.annotation.Priority}. * <p>Takes care of {@link Order @Order} and {@code @javax.annotation.Priority}.
* @param type the type to handle * @param type the type to handle
* @return the order value, or {@code null} if none can be found * @return the order value, or {@code null} if none can be found
* @see #getPriority(Class)
*/ */
public static Integer getOrder(Class<?> type) { public static Integer getOrder(Class<?> type) {
return getOrder(type, null); return getOrder(type, null);
@ -59,9 +60,10 @@ public abstract class OrderUtils {
/** /**
* Return the order on the specified {@code type}, or the specified * Return the order on the specified {@code type}, or the specified
* default value if none can be found. * default value if none can be found.
* <p>Take care of {@link Order @Order} and {@code @javax.annotation.Priority}. * <p>Takes care of {@link Order @Order} and {@code @javax.annotation.Priority}.
* @param type the type to handle * @param type the type to handle
* @return the priority value, or the specified default order if none can be found * @return the priority value, or the specified default order if none can be found
* @see #getPriority(Class)
*/ */
public static Integer getOrder(Class<?> type, Integer defaultOrder) { public static Integer getOrder(Class<?> type, Integer defaultOrder) {
Order order = AnnotationUtils.findAnnotation(type, Order.class); Order order = AnnotationUtils.findAnnotation(type, Order.class);