diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java
index d3bfa88f66..3ccbda3aea 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2017 the original author or authors.
+ * Copyright 2002-2018 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.
@@ -148,16 +148,13 @@ public interface BeanFactory {
*
Translates aliases back to the corresponding canonical bean name.
* Will ask the parent factory if the bean cannot be found in this factory instance.
* @param name the name of the bean to retrieve
- * @param requiredType type the bean must match. Can be an interface or superclass
- * of the actual class, or {@code null} for any match. For example, if the value
- * is {@code Object.class}, this method will succeed whatever the class of the
- * returned instance.
+ * @param requiredType type the bean must match; can be an interface or superclass
* @return an instance of the bean
* @throws NoSuchBeanDefinitionException if there is no such bean definition
* @throws BeanNotOfRequiredTypeException if the bean is not of the required type
* @throws BeansException if the bean could not be created
*/
- T getBean(String name, @Nullable Class requiredType) throws BeansException;
+ T getBean(String name, Class requiredType) throws BeansException;
/**
* Return an instance, which may be shared or independent, of the specified bean.
@@ -181,8 +178,7 @@ public interface BeanFactory {
* but may also be translated into a conventional by-name lookup based on the name
* of the given type. For more extensive retrieval operations across sets of beans,
* use {@link ListableBeanFactory} and/or {@link BeanFactoryUtils}.
- * @param requiredType type the bean must match; can be an interface or superclass.
- * {@code null} is disallowed.
+ * @param requiredType type the bean must match; can be an interface or superclass
* @return an instance of the single bean matching the required type
* @throws NoSuchBeanDefinitionException if no bean of the given type was found
* @throws NoUniqueBeanDefinitionException if more than one bean of the given type was found
@@ -200,8 +196,7 @@ public interface BeanFactory {
* but may also be translated into a conventional by-name lookup based on the name
* of the given type. For more extensive retrieval operations across sets of beans,
* use {@link ListableBeanFactory} and/or {@link BeanFactoryUtils}.
- * @param requiredType type the bean must match; can be an interface or superclass.
- * {@code null} is disallowed.
+ * @param requiredType type the bean must match; can be an interface or superclass
* @param args arguments to use when creating a bean instance using explicit arguments
* (only applied when creating a new instance as opposed to retrieving an existing one)
* @return an instance of the bean
@@ -213,6 +208,23 @@ public interface BeanFactory {
*/
T getBean(Class requiredType, Object... args) throws BeansException;
+ /**
+ * Return an provider for the specified bean, allowing for lazy on-demand retrieval
+ * of instances, including availability and uniqueness options.
+ * @param requiredType type the bean must match; can be an interface or superclass
+ * @return a corresponding provider handle
+ * @since 5.1
+ */
+ ObjectProvider getBeanProvider(Class requiredType);
+
+ /**
+ * Return an provider for the specified bean, allowing for lazy on-demand retrieval
+ * of instances, including availability and uniqueness options.
+ * @param requiredType type the bean must match; can be a generic type declaration
+ * @return a corresponding provider handle
+ * @since 5.1
+ */
+ ObjectProvider getBeanProvider(ResolvableType requiredType);
/**
* Does this bean factory contain a bean definition or externally registered singleton
@@ -298,7 +310,7 @@ public interface BeanFactory {
* @see #getBean
* @see #getType
*/
- boolean isTypeMatch(String name, @Nullable Class> typeToMatch) throws NoSuchBeanDefinitionException;
+ boolean isTypeMatch(String name, Class> typeToMatch) throws NoSuchBeanDefinitionException;
/**
* Determine the type of the bean with the given name. More specifically,
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/NoUniqueBeanDefinitionException.java b/spring-beans/src/main/java/org/springframework/beans/factory/NoUniqueBeanDefinitionException.java
index d7ebe487ab..f94e9d8805 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/NoUniqueBeanDefinitionException.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/NoUniqueBeanDefinitionException.java
@@ -19,6 +19,7 @@ package org.springframework.beans.factory;
import java.util.Arrays;
import java.util.Collection;
+import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
@@ -72,6 +73,29 @@ public class NoUniqueBeanDefinitionException extends NoSuchBeanDefinitionExcepti
this(type, Arrays.asList(beanNamesFound));
}
+ /**
+ * Create a new {@code NoUniqueBeanDefinitionException}.
+ * @param type required type of the non-unique bean
+ * @param beanNamesFound the names of all matching beans (as a Collection)
+ * @since 5.1
+ */
+ public NoUniqueBeanDefinitionException(ResolvableType type, Collection beanNamesFound) {
+ super(type, "expected single matching bean but found " + beanNamesFound.size() + ": " +
+ StringUtils.collectionToCommaDelimitedString(beanNamesFound));
+ this.numberOfBeansFound = beanNamesFound.size();
+ this.beanNamesFound = beanNamesFound;
+ }
+
+ /**
+ * Create a new {@code NoUniqueBeanDefinitionException}.
+ * @param type required type of the non-unique bean
+ * @param beanNamesFound the names of all matching beans (as an array)
+ * @since 5.1
+ */
+ public NoUniqueBeanDefinitionException(ResolvableType type, String... beanNamesFound) {
+ this(type, Arrays.asList(beanNamesFound));
+ }
+
/**
* Return the number of beans found when only one matching bean was expected.
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/ObjectProvider.java b/spring-beans/src/main/java/org/springframework/beans/factory/ObjectProvider.java
index 209444bcfa..7f4ef21cb4 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/ObjectProvider.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/ObjectProvider.java
@@ -16,8 +16,10 @@
package org.springframework.beans.factory;
+import java.util.Iterator;
import java.util.function.Consumer;
import java.util.function.Supplier;
+import java.util.stream.Stream;
import org.springframework.beans.BeansException;
import org.springframework.lang.Nullable;
@@ -26,11 +28,15 @@ import org.springframework.lang.Nullable;
* A variant of {@link ObjectFactory} designed specifically for injection points,
* allowing for programmatic optionality and lenient not-unique handling.
*
+ *
As of 5.1, this interface extends {@link Iterable} and provides {@link Stream}
+ * support. It can be therefore be used in {@code for} loops, provides {@link #forEach}
+ * iteration and allows for collection-style {@link #stream} access.
+ *
* @author Juergen Hoeller
* @since 4.3
* @param the object type
*/
-public interface ObjectProvider extends ObjectFactory {
+public interface ObjectProvider extends ObjectFactory, Iterable {
/**
* Return an instance (possibly shared or independent) of the object
@@ -130,4 +136,27 @@ public interface ObjectProvider extends ObjectFactory {
}
}
+ /**
+ * Return an {@link Iterator} over resolved object instances.
+ *
The default implementation returns a stream of one element or an
+ * empty stream if not available, resolved via {@link #getIfAvailable()}.
+ * @since 5.1
+ * @see #iterator()
+ */
+ default Stream stream() {
+ T instance = getIfAvailable();
+ return (instance != null ? Stream.of(instance) : Stream.empty());
+ }
+
}
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java
index 32cf7843d8..3e1faf1565 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java
@@ -199,6 +199,41 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable
return this.eager;
}
+ /**
+ * Return whether this descriptor allows for stream-style access to
+ * result instances.
+ *
By default, dependencies are strictly resolved to the declaration of
+ * the injection point and therefore only resolve multiple entries if the
+ * injection point is declared as an array, collection or map. This is
+ * indicated by returning {@code false} here.
+ *
Overriding this method to return {@code true} indicates that the
+ * injection point declares the bean type but the resolution is meant to
+ * end up in a {@link java.util.stream.Stream} for the declared bean type,
+ * with the caller handling the multi-instance case for the injection point.
+ * @since 5.1
+ */
+ public boolean isStreamAccess() {
+ return false;
+ }
+
+ /**
+ * Resolve the specified not-unique scenario: by default,
+ * throwing a {@link NoUniqueBeanDefinitionException}.
+ *
Subclasses may override this to select one of the instances or
+ * to opt out with no result at all through returning {@code null}.
+ * @param type the requested bean type
+ * @param matchingBeans a map of bean names and corresponding bean
+ * instances which have been pre-selected for the given type
+ * (qualifiers etc already applied)
+ * @return a bean instance to proceed with, or {@code null} for none
+ * @throws BeansException in case of the not-unique scenario being fatal
+ * @since 5.1
+ */
+ @Nullable
+ public Object resolveNotUnique(ResolvableType type, Map matchingBeans) throws BeansException {
+ throw new NoUniqueBeanDefinitionException(type, matchingBeans.keySet());
+ }
+
/**
* Resolve the specified not-unique scenario: by default,
* throwing a {@link NoUniqueBeanDefinitionException}.
@@ -211,7 +246,9 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable
* @return a bean instance to proceed with, or {@code null} for none
* @throws BeansException in case of the not-unique scenario being fatal
* @since 4.3
+ * @deprecated as of 5.1, in favor of {@link #resolveNotUnique(ResolvableType, Map)}
*/
+ @Deprecated
@Nullable
public Object resolveNotUnique(Class> type, Map matchingBeans) throws BeansException {
throw new NoUniqueBeanDefinitionException(type, matchingBeans.keySet());
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 869f0fc642..aa7da4c04c 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
@@ -200,7 +200,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
}
@Override
- public T getBean(String name, @Nullable Class requiredType) throws BeansException {
+ public T getBean(String name, Class requiredType) throws BeansException {
return doGetBean(name, requiredType, null, false);
}
@@ -277,10 +277,13 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
- else {
+ else if (requiredType != null) {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
+ else {
+ return (T) parentBeanFactory.getBean(nameToLookup);
+ }
}
if (!typeCheckOnly) {
@@ -586,7 +589,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
}
@Override
- public boolean isTypeMatch(String name, @Nullable Class> typeToMatch) throws NoSuchBeanDefinitionException {
+ public boolean isTypeMatch(String name, Class> typeToMatch) throws NoSuchBeanDefinitionException {
return isTypeMatch(name, ResolvableType.forRawClass(typeToMatch));
}
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java
index 0e1e476a1d..2369fc4043 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java
@@ -43,10 +43,12 @@ import org.springframework.beans.TypeMismatchException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.InjectionPoint;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.UnsatisfiedDependencyException;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
import org.springframework.beans.factory.config.DependencyDescriptor;
+import org.springframework.core.CollectionFactory;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.MethodParameter;
import org.springframework.core.NamedThreadLocal;
@@ -133,7 +135,7 @@ class ConstructorResolver {
}
}
if (argsToResolve != null) {
- argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve);
+ argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true);
}
}
@@ -195,7 +197,7 @@ class ConstructorResolver {
}
}
argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
- getUserDeclaredConstructor(candidate), autowiring);
+ getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1);
}
catch (UnsatisfiedDependencyException ex) {
if (logger.isTraceEnabled()) {
@@ -407,7 +409,7 @@ class ConstructorResolver {
}
}
if (argsToResolve != null) {
- argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve);
+ argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true);
}
}
@@ -471,8 +473,8 @@ class ConstructorResolver {
if (pnd != null) {
paramNames = pnd.getParameterNames(candidate);
}
- argsHolder = createArgumentArray(
- beanName, mbd, resolvedValues, bw, paramTypes, paramNames, candidate, autowiring);
+ argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw,
+ paramTypes, paramNames, candidate, autowiring, candidates.length == 1);
}
catch (UnsatisfiedDependencyException ex) {
if (logger.isTraceEnabled()) {
@@ -654,7 +656,7 @@ class ConstructorResolver {
private ArgumentsHolder createArgumentArray(
String beanName, RootBeanDefinition mbd, @Nullable ConstructorArgumentValues resolvedValues,
BeanWrapper bw, Class>[] paramTypes, @Nullable String[] paramNames, Executable executable,
- boolean autowiring) throws UnsatisfiedDependencyException {
+ boolean autowiring, boolean fallback) throws UnsatisfiedDependencyException {
TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
TypeConverter converter = (customConverter != null ? customConverter : bw);
@@ -720,8 +722,8 @@ class ConstructorResolver {
"] - did you specify the correct bean references as arguments?");
}
try {
- Object autowiredArgument =
- resolveAutowiredArgument(methodParam, beanName, autowiredBeanNames, converter);
+ Object autowiredArgument = resolveAutowiredArgument(
+ methodParam, beanName, autowiredBeanNames, converter, fallback);
args.rawArguments[paramIndex] = autowiredArgument;
args.arguments[paramIndex] = autowiredArgument;
args.preparedArguments[paramIndex] = new AutowiredArgumentMarker();
@@ -749,8 +751,8 @@ class ConstructorResolver {
/**
* Resolve the prepared arguments stored in the given bean definition.
*/
- private Object[] resolvePreparedArguments(
- String beanName, RootBeanDefinition mbd, BeanWrapper bw, Executable executable, Object[] argsToResolve) {
+ private Object[] resolvePreparedArguments(String beanName, RootBeanDefinition mbd, BeanWrapper bw,
+ Executable executable, Object[] argsToResolve, boolean fallback) {
TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
TypeConverter converter = (customConverter != null ? customConverter : bw);
@@ -764,7 +766,7 @@ class ConstructorResolver {
MethodParameter methodParam = MethodParameter.forExecutable(executable, argIndex);
GenericTypeResolver.resolveParameterType(methodParam, executable.getDeclaringClass());
if (argValue instanceof AutowiredArgumentMarker) {
- argValue = resolveAutowiredArgument(methodParam, beanName, null, converter);
+ argValue = resolveAutowiredArgument(methodParam, beanName, null, converter, fallback);
}
else if (argValue instanceof BeanMetadataElement) {
argValue = valueResolver.resolveValueIfNecessary("constructor argument", argValue);
@@ -806,17 +808,33 @@ class ConstructorResolver {
*/
@Nullable
protected Object resolveAutowiredArgument(MethodParameter param, String beanName,
- @Nullable Set autowiredBeanNames, TypeConverter typeConverter) {
+ @Nullable Set autowiredBeanNames, TypeConverter typeConverter, boolean fallback) {
- if (InjectionPoint.class.isAssignableFrom(param.getParameterType())) {
+ Class> paramType = param.getParameterType();
+ if (InjectionPoint.class.isAssignableFrom(paramType)) {
InjectionPoint injectionPoint = currentInjectionPoint.get();
if (injectionPoint == null) {
throw new IllegalStateException("No current InjectionPoint available for " + param);
}
return injectionPoint;
}
- return this.beanFactory.resolveDependency(
- new DependencyDescriptor(param, true), beanName, autowiredBeanNames, typeConverter);
+ try {
+ return this.beanFactory.resolveDependency(
+ new DependencyDescriptor(param, true), beanName, autowiredBeanNames, typeConverter);
+ }
+ catch (NoSuchBeanDefinitionException ex) {
+ if (fallback) {
+ // Single constructor or factory method -> let's return an
+ // empty collection for a non-null collection parameter.
+ if (CollectionFactory.isApproximableCollectionType(paramType)) {
+ return CollectionFactory.createCollection(paramType, 0);
+ }
+ else if (CollectionFactory.isApproximableMapType(paramType)) {
+ return CollectionFactory.createMap(paramType, 0);
+ }
+ }
+ throw ex;
+ }
}
static InjectionPoint setCurrentInjectionPoint(@Nullable InjectionPoint injectionPoint) {
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 1d9e0e68c2..2ed1c5aba3 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
@@ -40,6 +40,7 @@ import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Stream;
import javax.inject.Provider;
import org.springframework.beans.BeanUtils;
@@ -333,17 +334,80 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
return getBean(requiredType, (Object[]) null);
}
+ @SuppressWarnings("unchecked")
@Override
public T getBean(Class requiredType, @Nullable Object... args) throws BeansException {
- NamedBeanHolder namedBean = resolveNamedBean(requiredType, args);
+ Object resolved = resolveBean(ResolvableType.forRawClass(requiredType), args, false);
+ if (resolved == null) {
+ throw new NoSuchBeanDefinitionException(requiredType);
+ }
+ return (T) resolved;
+ }
+
+ @Override
+ public ObjectProvider getBeanProvider(Class requiredType) throws BeansException {
+ return getBeanProvider(ResolvableType.forRawClass(requiredType));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public ObjectProvider getBeanProvider(ResolvableType requiredType) {
+ return new BeanObjectProvider() {
+ @Override
+ public T getObject() throws BeansException {
+ T resolved = resolveBean(requiredType, null, false);
+ if (resolved == null) {
+ throw new NoSuchBeanDefinitionException(requiredType);
+ }
+ return resolved;
+ }
+ @Override
+ public T getObject(Object... args) throws BeansException {
+ T resolved = resolveBean(requiredType, args, false);
+ if (resolved == null) {
+ throw new NoSuchBeanDefinitionException(requiredType);
+ }
+ return resolved;
+ }
+ @Override
+ @Nullable
+ public T getIfAvailable() throws BeansException {
+ return resolveBean(requiredType, null, false);
+ }
+ @Override
+ @Nullable
+ public T getIfUnique() throws BeansException {
+ return resolveBean(requiredType, null, true);
+ }
+ @Override
+ public Stream stream() {
+ return Arrays.stream(getBeanNamesForType(requiredType))
+ .map(name -> (T) getBean(name))
+ .filter(bean -> !(bean instanceof NullBean));
+ }
+ };
+ }
+
+ @Nullable
+ private T resolveBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) {
+ NamedBeanHolder namedBean = resolveNamedBean(requiredType, args, nonUniqueAsNull);
if (namedBean != null) {
return namedBean.getBeanInstance();
}
BeanFactory parent = getParentBeanFactory();
- if (parent != null) {
- return (args != null ? parent.getBean(requiredType, args) : parent.getBean(requiredType));
+ if (parent instanceof DefaultListableBeanFactory) {
+ return ((DefaultListableBeanFactory) parent).resolveBean(requiredType, args, nonUniqueAsNull);
}
- throw new NoSuchBeanDefinitionException(requiredType);
+ else if (parent != null) {
+ ObjectProvider parentProvider = parent.getBeanProvider(requiredType);
+ if (args != null) {
+ return parentProvider.getObject(args);
+ }
+ else {
+ return (nonUniqueAsNull ? parentProvider.getIfUnique() : parentProvider.getIfAvailable());
+ }
+ }
+ return null;
}
@@ -978,7 +1042,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
@Override
public NamedBeanHolder resolveNamedBean(Class requiredType) throws BeansException {
- NamedBeanHolder namedBean = resolveNamedBean(requiredType, (Object[]) null);
+ NamedBeanHolder namedBean = resolveNamedBean(ResolvableType.forRawClass(requiredType), null, false);
if (namedBean != null) {
return namedBean;
}
@@ -991,8 +1055,12 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
@SuppressWarnings("unchecked")
@Nullable
- private NamedBeanHolder resolveNamedBean(Class requiredType, @Nullable Object... args) throws BeansException {
+ private NamedBeanHolder resolveNamedBean(
+ ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) throws BeansException {
+
Assert.notNull(requiredType, "Required type must not be null");
+ Class> clazz = requiredType.getRawClass();
+ Assert.notNull(clazz, "Required type must have a raw Class");
String[] candidateNames = getBeanNamesForType(requiredType);
if (candidateNames.length > 1) {
@@ -1009,7 +1077,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
if (candidateNames.length == 1) {
String beanName = candidateNames[0];
- return new NamedBeanHolder<>(beanName, getBean(beanName, requiredType, args));
+ return new NamedBeanHolder<>(beanName, (T) getBean(beanName, clazz, args));
}
else if (candidateNames.length > 1) {
Map candidates = new LinkedHashMap<>(candidateNames.length);
@@ -1022,18 +1090,20 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
candidates.put(beanName, getType(beanName));
}
}
- String candidateName = determinePrimaryCandidate(candidates, requiredType);
+ String candidateName = determinePrimaryCandidate(candidates, clazz);
if (candidateName == null) {
- candidateName = determineHighestPriorityCandidate(candidates, requiredType);
+ candidateName = determineHighestPriorityCandidate(candidates, clazz);
}
if (candidateName != null) {
Object beanInstance = candidates.get(candidateName);
if (beanInstance == null || beanInstance instanceof Class) {
- beanInstance = getBean(candidateName, requiredType, args);
+ beanInstance = getBean(candidateName, clazz, args);
}
return new NamedBeanHolder<>(candidateName, (T) beanInstance);
}
- throw new NoUniqueBeanDefinitionException(requiredType, candidates.keySet());
+ if (!nonUniqueAsNull) {
+ throw new NoUniqueBeanDefinitionException(requiredType, candidates.keySet());
+ }
}
return null;
@@ -1110,7 +1180,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
- return descriptor.resolveNotUnique(type, matchingBeans);
+ return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
}
else {
// In case of an optional Collection/Map, silently ignore a non-unique case:
@@ -1156,7 +1226,16 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
@Nullable Set autowiredBeanNames, @Nullable TypeConverter typeConverter) {
Class> type = descriptor.getDependencyType();
- if (type.isArray()) {
+
+ if (descriptor.isStreamAccess()) {
+ Map matchingBeans = findAutowireCandidates(beanName, type,
+ new MultiElementDescriptor(descriptor));
+ if (autowiredBeanNames != null) {
+ autowiredBeanNames.addAll(matchingBeans.keySet());
+ }
+ return matchingBeans.values().stream();
+ }
+ else if (type.isArray()) {
Class> componentType = type.getComponentType();
ResolvableType resolvableType = descriptor.getResolvableType();
Class> resolvedArrayType = resolvableType.resolve();
@@ -1645,10 +1724,14 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
}
+ private interface BeanObjectProvider extends ObjectProvider, Serializable {
+ }
+
+
/**
* Serializable ObjectFactory/ObjectProvider for lazy resolution of a dependency.
*/
- private class DependencyObjectProvider implements ObjectProvider