diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java index 1f4cc19f1e..0a5abbd9ae 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java @@ -131,16 +131,14 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp private ConversionService conversionService; /** Custom PropertyEditorRegistrars to apply to the beans of this factory */ - private final Set propertyEditorRegistrars = - new LinkedHashSet<>(4); + private final Set propertyEditorRegistrars = new LinkedHashSet<>(4); + + /** Custom PropertyEditors to apply to the beans of this factory */ + private final Map, Class> customEditors = new HashMap<>(4); /** A custom TypeConverter to use, overriding the default PropertyEditor mechanism */ private TypeConverter typeConverter; - /** Custom PropertyEditors to apply to the beans of this factory */ - private final Map, Class> customEditors = - new HashMap<>(4); - /** String resolvers to apply e.g. to annotation attribute values */ private final List embeddedValueResolvers = new LinkedList<>(); @@ -919,10 +917,12 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp setBeanClassLoader(otherFactory.getBeanClassLoader()); setCacheBeanMetadata(otherFactory.isCacheBeanMetadata()); setBeanExpressionResolver(otherFactory.getBeanExpressionResolver()); + setConversionService(otherFactory.getConversionService()); if (otherFactory instanceof AbstractBeanFactory) { AbstractBeanFactory otherAbstractFactory = (AbstractBeanFactory) otherFactory; - this.customEditors.putAll(otherAbstractFactory.customEditors); this.propertyEditorRegistrars.addAll(otherAbstractFactory.propertyEditorRegistrars); + this.customEditors.putAll(otherAbstractFactory.customEditors); + this.typeConverter = otherAbstractFactory.typeConverter; this.beanPostProcessors.addAll(otherAbstractFactory.beanPostProcessors); this.hasInstantiationAwareBeanPostProcessors = this.hasInstantiationAwareBeanPostProcessors || otherAbstractFactory.hasInstantiationAwareBeanPostProcessors; @@ -933,6 +933,10 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp } else { setTypeConverter(otherFactory.getTypeConverter()); + String[] otherScopeNames = otherFactory.getRegisteredScopeNames(); + for (String scopeName : otherScopeNames) { + this.scopes.put(scopeName, otherFactory.getRegisteredScope(scopeName)); + } } } 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 5a6d372574..1e763db2c7 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 @@ -43,6 +43,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import javax.inject.Provider; +import org.springframework.beans.BeanUtils; import org.springframework.beans.BeansException; import org.springframework.beans.TypeConverter; import org.springframework.beans.factory.BeanCreationException; @@ -256,6 +257,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto /** * Set a {@link java.util.Comparator} for dependency Lists and arrays. + * @since 4.0 * @see org.springframework.core.OrderComparator * @see org.springframework.core.annotation.AnnotationAwareOrderComparator */ @@ -265,6 +267,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto /** * Return the dependency comparator for this BeanFactory (may be {@code null}. + * @since 4.0 */ public Comparator getDependencyComparator() { return this.dependencyComparator; @@ -279,11 +282,10 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto Assert.notNull(autowireCandidateResolver, "AutowireCandidateResolver must not be null"); if (autowireCandidateResolver instanceof BeanFactoryAware) { if (System.getSecurityManager() != null) { - final BeanFactory target = this; AccessController.doPrivileged(new PrivilegedAction() { @Override public Object run() { - ((BeanFactoryAware) autowireCandidateResolver).setBeanFactory(target); + ((BeanFactoryAware) autowireCandidateResolver).setBeanFactory(DefaultListableBeanFactory.this); return null; } }, getAccessControlContext()); @@ -310,7 +312,10 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto DefaultListableBeanFactory otherListableFactory = (DefaultListableBeanFactory) otherFactory; this.allowBeanDefinitionOverriding = otherListableFactory.allowBeanDefinitionOverriding; this.allowEagerClassLoading = otherListableFactory.allowEagerClassLoading; - this.autowireCandidateResolver = otherListableFactory.autowireCandidateResolver; + this.dependencyComparator = otherListableFactory.dependencyComparator; + // A clone of the AutowireCandidateResolver since it is potentially BeanFactoryAware... + setAutowireCandidateResolver(BeanUtils.instantiateClass(getAutowireCandidateResolver().getClass())); + // Make resolvable dependencies (e.g. ResourceLoader) available here as well... this.resolvableDependencies.putAll(otherListableFactory.resolvableDependencies); } } @@ -357,7 +362,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto @Override public String[] getBeanDefinitionNames() { if (this.frozenBeanDefinitionNames != null) { - return this.frozenBeanDefinitionNames; + return this.frozenBeanDefinitionNames.clone(); } else { return StringUtils.toStringArray(this.beanDefinitionNames); @@ -1256,8 +1261,9 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto addCandidateEntry(result, candidateName, descriptor, requiredType); } } - if (result.isEmpty()) { - // Consider self references before as a final pass + if (result.isEmpty() && !(descriptor instanceof MultiElementDependencyDescriptor)) { + // Consider self references as a final pass... + // but not as collection elements, just for direct dependency declarations. for (String candidateName : candidateNames) { if (isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, fallbackDescriptor)) { addCandidateEntry(result, candidateName, descriptor, requiredType); @@ -1466,10 +1472,10 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto Class targetType = mbd.getTargetType(); if (targetType != null && type.isAssignableFrom(targetType) && isAutowireCandidate(beanName, mbd, descriptor, getAutowireCandidateResolver())) { - // Probably a poxy interfering with target type match -> throw meaningful exception. + // Probably a proxy interfering with target type match -> throw meaningful exception. Object beanInstance = getSingleton(beanName, false); Class beanType = (beanInstance != null ? beanInstance.getClass() : predictBeanType(beanName, mbd)); - if (type != beanType) { + if (!type.isAssignableFrom((beanType))) { throw new BeanNotOfRequiredTypeException(beanName, type, beanType); } } diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java index 3cd889c67e..4d6207deab 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java @@ -776,6 +776,7 @@ public class DefaultListableBeanFactoryTests { private void testSingleTestBean(ListableBeanFactory lbf) { assertTrue("1 beans defined", lbf.getBeanDefinitionCount() == 1); String[] names = lbf.getBeanDefinitionNames(); + assertTrue(names != lbf.getBeanDefinitionNames()); assertTrue("Array length == 1", names.length == 1); assertTrue("0th element == test", names[0].equals("test")); TestBean tb = (TestBean) lbf.getBean("test"); 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 16f578f005..ec83ce0589 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 @@ -29,6 +29,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Properties; @@ -978,11 +979,59 @@ public class AutowiredAnnotationBeanPostProcessorTests { AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); bpp.setBeanFactory(bf); bf.addBeanPostProcessor(bpp); - RootBeanDefinition bd = new RootBeanDefinition(SelfInjectionBean.class); - bf.registerBeanDefinition("annotatedBean", bd); + bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SelfInjectionBean.class)); SelfInjectionBean bean = (SelfInjectionBean) bf.getBean("annotatedBean"); - assertSame(bean, bean.selfReference); + assertSame(bean, bean.reference); + assertNull(bean.referenceCollection); + } + + @Test + public void testSelfReferenceWithOther() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver()); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SelfInjectionBean.class)); + bf.registerBeanDefinition("annotatedBean2", new RootBeanDefinition(SelfInjectionBean.class)); + + SelfInjectionBean bean = (SelfInjectionBean) bf.getBean("annotatedBean"); + SelfInjectionBean bean2 = (SelfInjectionBean) bf.getBean("annotatedBean2"); + assertSame(bean2, bean.reference); + assertEquals(1, bean.referenceCollection.size()); + assertSame(bean2, bean.referenceCollection.get(0)); + } + + @Test + public void testSelfReferenceCollection() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver()); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SelfInjectionCollectionBean.class)); + + SelfInjectionCollectionBean bean = (SelfInjectionCollectionBean) bf.getBean("annotatedBean"); + assertSame(bean, bean.reference); + assertNull(bean.referenceCollection); + } + + @Test + public void testSelfReferenceCollectionWithOther() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver()); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SelfInjectionCollectionBean.class)); + bf.registerBeanDefinition("annotatedBean2", new RootBeanDefinition(SelfInjectionCollectionBean.class)); + + SelfInjectionCollectionBean bean = (SelfInjectionCollectionBean) bf.getBean("annotatedBean"); + SelfInjectionCollectionBean bean2 = (SelfInjectionCollectionBean) bf.getBean("annotatedBean2"); + assertSame(bean2, bean.reference); + assertSame(1, bean2.referenceCollection.size()); + assertSame(bean2, bean.referenceCollection.get(0)); } @Test @@ -2582,7 +2631,21 @@ public class AutowiredAnnotationBeanPostProcessorTests { public static class SelfInjectionBean { @Autowired - public SelfInjectionBean selfReference; + public SelfInjectionBean reference; + + @Autowired(required = false) + public List referenceCollection; + } + + + @SuppressWarnings("serial") + public static class SelfInjectionCollectionBean extends LinkedList { + + @Autowired + public SelfInjectionCollectionBean reference; + + @Autowired(required = false) + public List referenceCollection; }