matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
- if (descriptor.isRequired()) {
+ if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
@@ -1112,7 +1112,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
if (matchingBeans.size() > 1) {
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
- if (descriptor.isRequired() || !indicatesMultipleBeans(type)) {
+ if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
return descriptor.resolveNotUnique(type, matchingBeans);
}
else {
@@ -1217,6 +1217,13 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
}
}
+ private boolean isRequired(DependencyDescriptor descriptor) {
+ AutowireCandidateResolver resolver = getAutowireCandidateResolver();
+ return (resolver instanceof SimpleAutowireCandidateResolver ?
+ ((SimpleAutowireCandidateResolver) resolver).isRequired(descriptor) :
+ descriptor.isRequired());
+ }
+
private boolean indicatesMultipleBeans(Class> type) {
return (type.isArray() || (type.isInterface() &&
(Collection.class.isAssignableFrom(type) || Map.class.isAssignableFrom(type))));
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/GenericTypeAwareAutowireCandidateResolver.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/GenericTypeAwareAutowireCandidateResolver.java
index b204d551c3..7ffbed3e0e 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/support/GenericTypeAwareAutowireCandidateResolver.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/GenericTypeAwareAutowireCandidateResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 the original author or authors.
+ * Copyright 2002-2017 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.
@@ -40,7 +40,8 @@ import org.springframework.util.ClassUtils;
* @author Juergen Hoeller
* @since 4.0
*/
-public class GenericTypeAwareAutowireCandidateResolver implements AutowireCandidateResolver, BeanFactoryAware {
+public class GenericTypeAwareAutowireCandidateResolver extends SimpleAutowireCandidateResolver
+ implements BeanFactoryAware {
private BeanFactory beanFactory;
@@ -57,8 +58,8 @@ public class GenericTypeAwareAutowireCandidateResolver implements AutowireCandid
@Override
public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) {
- if (!bdHolder.getBeanDefinition().isAutowireCandidate()) {
- // if explicitly false, do not proceed with any other checks
+ if (!super.isAutowireCandidate(bdHolder, descriptor)) {
+ // If explicitly false, do not proceed with any other checks...
return false;
}
return (descriptor == null || checkGenericTypeMatch(bdHolder, descriptor));
@@ -166,23 +167,4 @@ public class GenericTypeAwareAutowireCandidateResolver implements AutowireCandid
return null;
}
-
- /**
- * This implementation always returns {@code null}, leaving suggested value support up
- * to subclasses.
- */
- @Override
- public Object getSuggestedValue(DependencyDescriptor descriptor) {
- return null;
- }
-
- /**
- * This implementation always returns {@code null}, leaving lazy resolution support up
- * to subclasses.
- */
- @Override
- public Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor, String beanName) {
- return null;
- }
-
}
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/SimpleAutowireCandidateResolver.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/SimpleAutowireCandidateResolver.java
index 4d29b95b6e..803810d834 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/support/SimpleAutowireCandidateResolver.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/SimpleAutowireCandidateResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2013 the original author or authors.
+ * Copyright 2002-2017 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.
@@ -16,7 +16,6 @@
package org.springframework.beans.factory.support;
-import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.DependencyDescriptor;
@@ -27,20 +26,27 @@ import org.springframework.beans.factory.config.DependencyDescriptor;
* @author Mark Fisher
* @author Juergen Hoeller
* @since 2.5
- * @see BeanDefinition#isAutowireCandidate()
*/
public class SimpleAutowireCandidateResolver implements AutowireCandidateResolver {
- /**
- * Determine if the provided bean definition is an autowire candidate.
- * To be considered a candidate the bean's autowire-candidate
- * attribute must not have been set to 'false'.
- */
@Override
public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) {
return bdHolder.getBeanDefinition().isAutowireCandidate();
}
+ /**
+ * Determine whether the given descriptor is effectively required.
+ *
The default implementation checks {@link DependencyDescriptor#isRequired()}.
+ * @param descriptor the descriptor for the target method parameter or field
+ * @return whether the descriptor is marked as required or possibly indicating
+ * non-required status some other way (e.g. through a parameter annotation)
+ * @since 4.3.9
+ * @see DependencyDescriptor#isRequired()
+ */
+ public boolean isRequired(DependencyDescriptor descriptor) {
+ return descriptor.isRequired();
+ }
+
@Override
public Object getSuggestedValue(DependencyDescriptor descriptor) {
return null;
diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java
index d193e33c02..9b0a22eb71 100644
--- a/spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java
+++ b/spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java
@@ -699,8 +699,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(bf);
bf.addBeanPostProcessor(bpp);
- bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(
- ConstructorsCollectionResourceInjectionBean.class));
+ bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ConstructorsCollectionResourceInjectionBean.class));
TestBean tb = new TestBean();
bf.registerSingleton("testBean", tb);
FixedOrder2NestedTestBean ntb1 = new FixedOrder2NestedTestBean();
@@ -717,6 +716,46 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.destroySingletons();
}
+ @Test
+ public void testSingleConstructorInjectionWithMultipleCandidatesAsOrderedCollection() {
+ DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
+ bf.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
+ AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
+ bpp.setBeanFactory(bf);
+ bf.addBeanPostProcessor(bpp);
+ bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SingleConstructorCollectionInjectionBean.class));
+ TestBean tb = new TestBean();
+ bf.registerSingleton("testBean", tb);
+ FixedOrder2NestedTestBean ntb1 = new FixedOrder2NestedTestBean();
+ bf.registerSingleton("nestedTestBean1", ntb1);
+ FixedOrder1NestedTestBean ntb2 = new FixedOrder1NestedTestBean();
+ bf.registerSingleton("nestedTestBean2", ntb2);
+
+ SingleConstructorCollectionInjectionBean bean = (SingleConstructorCollectionInjectionBean) bf.getBean("annotatedBean");
+ assertSame(tb, bean.getTestBean());
+ assertEquals(2, bean.getNestedTestBeans().size());
+ assertSame(ntb2, bean.getNestedTestBeans().get(0));
+ assertSame(ntb1, bean.getNestedTestBeans().get(1));
+ bf.destroySingletons();
+ }
+
+ @Test
+ public void testSingleConstructorInjectionWithEmptyCollection() {
+ DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
+ bf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
+ AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
+ bpp.setBeanFactory(bf);
+ bf.addBeanPostProcessor(bpp);
+ bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SingleConstructorCollectionInjectionBean.class));
+ TestBean tb = new TestBean();
+ bf.registerSingleton("testBean", tb);
+
+ SingleConstructorCollectionInjectionBean bean = (SingleConstructorCollectionInjectionBean) bf.getBean("annotatedBean");
+ assertSame(tb, bean.getTestBean());
+ assertNull(bean.getNestedTestBeans());
+ bf.destroySingletons();
+ }
+
@Test
public void testConstructorResourceInjectionWithMultipleCandidatesAndFallback() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
@@ -2751,6 +2790,28 @@ public class AutowiredAnnotationBeanPostProcessorTests {
}
+ public static class SingleConstructorCollectionInjectionBean {
+
+ private ITestBean testBean;
+
+ private List nestedTestBeans;
+
+ public SingleConstructorCollectionInjectionBean(ITestBean testBean,
+ @Autowired(required = false) List nestedTestBeans) {
+ this.testBean = testBean;
+ this.nestedTestBeans = nestedTestBeans;
+ }
+
+ public ITestBean getTestBean() {
+ return this.testBean;
+ }
+
+ public List getNestedTestBeans() {
+ return this.nestedTestBeans;
+ }
+ }
+
+
@SuppressWarnings("serial")
public static class MyTestBeanMap extends LinkedHashMap {
}