Support by-type constructor references via RuntimeBeanReference
Closes gh-28728
This commit is contained in:
parent
a21b27e6d9
commit
d2e27ad754
|
@ -30,9 +30,7 @@ import java.util.function.Function;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.FactoryBean;
|
import org.springframework.beans.factory.FactoryBean;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
|
@ -40,6 +38,7 @@ import org.springframework.beans.factory.config.BeanReference;
|
||||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||||
import org.springframework.beans.factory.config.ConstructorArgumentValues;
|
import org.springframework.beans.factory.config.ConstructorArgumentValues;
|
||||||
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
|
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
|
||||||
|
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||||
import org.springframework.beans.factory.support.RegisteredBean;
|
import org.springframework.beans.factory.support.RegisteredBean;
|
||||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||||
|
@ -62,57 +61,52 @@ import org.springframework.util.ReflectionUtils;
|
||||||
*/
|
*/
|
||||||
class ConstructorOrFactoryMethodResolver {
|
class ConstructorOrFactoryMethodResolver {
|
||||||
|
|
||||||
private static final Log logger = LogFactory
|
|
||||||
.getLog(ConstructorOrFactoryMethodResolver.class);
|
|
||||||
|
|
||||||
|
|
||||||
private final ConfigurableBeanFactory beanFactory;
|
private final ConfigurableBeanFactory beanFactory;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
private final ClassLoader classLoader;
|
private final ClassLoader classLoader;
|
||||||
|
|
||||||
|
|
||||||
ConstructorOrFactoryMethodResolver(ConfigurableBeanFactory beanFactory) {
|
ConstructorOrFactoryMethodResolver(ConfigurableBeanFactory beanFactory) {
|
||||||
this.beanFactory = beanFactory;
|
this.beanFactory = beanFactory;
|
||||||
this.classLoader = (beanFactory.getBeanClassLoader() != null)
|
this.classLoader = (beanFactory.getBeanClassLoader() != null ?
|
||||||
? beanFactory.getBeanClassLoader() : ClassUtils.getDefaultClassLoader();
|
beanFactory.getBeanClassLoader() : ClassUtils.getDefaultClassLoader());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Nullable
|
||||||
Executable resolve(BeanDefinition beanDefinition) {
|
Executable resolve(BeanDefinition beanDefinition) {
|
||||||
Supplier<ResolvableType> beanType = () -> getBeanType(beanDefinition);
|
Supplier<ResolvableType> beanType = () -> getBeanType(beanDefinition);
|
||||||
List<ResolvableType> valueTypes = beanDefinition.hasConstructorArgumentValues()
|
List<ResolvableType> valueTypes = (beanDefinition.hasConstructorArgumentValues() ?
|
||||||
? determineParameterValueTypes(
|
determineParameterValueTypes(beanDefinition.getConstructorArgumentValues()) :
|
||||||
beanDefinition.getConstructorArgumentValues())
|
Collections.emptyList());
|
||||||
: Collections.emptyList();
|
|
||||||
Method resolvedFactoryMethod = resolveFactoryMethod(beanDefinition, valueTypes);
|
Method resolvedFactoryMethod = resolveFactoryMethod(beanDefinition, valueTypes);
|
||||||
if (resolvedFactoryMethod != null) {
|
if (resolvedFactoryMethod != null) {
|
||||||
return resolvedFactoryMethod;
|
return resolvedFactoryMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
Class<?> factoryBeanClass = getFactoryBeanClass(beanDefinition);
|
Class<?> factoryBeanClass = getFactoryBeanClass(beanDefinition);
|
||||||
if (factoryBeanClass != null && !factoryBeanClass
|
if (factoryBeanClass != null && !factoryBeanClass.equals(beanDefinition.getResolvableType().toClass())) {
|
||||||
.equals(beanDefinition.getResolvableType().toClass())) {
|
|
||||||
ResolvableType resolvableType = beanDefinition.getResolvableType();
|
ResolvableType resolvableType = beanDefinition.getResolvableType();
|
||||||
boolean isCompatible = ResolvableType.forClass(factoryBeanClass)
|
boolean isCompatible = ResolvableType.forClass(factoryBeanClass)
|
||||||
.as(FactoryBean.class).getGeneric(0).isAssignableFrom(resolvableType);
|
.as(FactoryBean.class).getGeneric(0).isAssignableFrom(resolvableType);
|
||||||
Assert.state(isCompatible,
|
Assert.state(isCompatible, () -> String.format(
|
||||||
() -> String.format(
|
|
||||||
"Incompatible target type '%s' for factory bean '%s'",
|
"Incompatible target type '%s' for factory bean '%s'",
|
||||||
resolvableType.toClass().getName(),
|
resolvableType.toClass().getName(), factoryBeanClass.getName()));
|
||||||
factoryBeanClass.getName()));
|
return resolveConstructor(() -> ResolvableType.forClass(factoryBeanClass), valueTypes);
|
||||||
return resolveConstructor(() -> ResolvableType.forClass(factoryBeanClass),
|
|
||||||
valueTypes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Executable resolvedConstructor = resolveConstructor(beanType, valueTypes);
|
Executable resolvedConstructor = resolveConstructor(beanType, valueTypes);
|
||||||
if (resolvedConstructor != null) {
|
if (resolvedConstructor != null) {
|
||||||
return resolvedConstructor;
|
return resolvedConstructor;
|
||||||
}
|
}
|
||||||
Executable resolvedConstructorOrFactoryMethod = getField(beanDefinition,
|
|
||||||
"resolvedConstructorOrFactoryMethod", Executable.class);
|
Field field = ReflectionUtils.findField(RootBeanDefinition.class, "resolvedConstructorOrFactoryMethod");
|
||||||
if (resolvedConstructorOrFactoryMethod != null) {
|
if (field != null) {
|
||||||
logger.error(
|
ReflectionUtils.makeAccessible(field);
|
||||||
"resolvedConstructorOrFactoryMethod required for " + beanDefinition);
|
return (Executable) ReflectionUtils.getField(field, beanDefinition);
|
||||||
return resolvedConstructorOrFactoryMethod;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,15 +126,19 @@ class ConstructorOrFactoryMethodResolver {
|
||||||
return ResolvableType.forClass(loadClass(valueHolder.getType()));
|
return ResolvableType.forClass(loadClass(valueHolder.getType()));
|
||||||
}
|
}
|
||||||
Object value = valueHolder.getValue();
|
Object value = valueHolder.getValue();
|
||||||
if (value instanceof BeanReference) {
|
if (value instanceof BeanReference br) {
|
||||||
return ResolvableType.forClass(this.beanFactory
|
if (value instanceof RuntimeBeanReference rbr) {
|
||||||
.getType(((BeanReference) value).getBeanName(), false));
|
if (rbr.getBeanType() != null) {
|
||||||
|
return ResolvableType.forClass(rbr.getBeanType());
|
||||||
}
|
}
|
||||||
if (value instanceof BeanDefinition) {
|
|
||||||
return extractTypeFromBeanDefinition(getBeanType((BeanDefinition) value));
|
|
||||||
}
|
}
|
||||||
if (value instanceof Class<?>) {
|
return ResolvableType.forClass(this.beanFactory.getType(br.getBeanName(), false));
|
||||||
return ResolvableType.forClassWithGenerics(Class.class, (Class<?>) value);
|
}
|
||||||
|
if (value instanceof BeanDefinition bd) {
|
||||||
|
return extractTypeFromBeanDefinition(getBeanType(bd));
|
||||||
|
}
|
||||||
|
if (value instanceof Class<?> clazz) {
|
||||||
|
return ResolvableType.forClassWithGenerics(Class.class, clazz);
|
||||||
}
|
}
|
||||||
return ResolvableType.forInstance(value);
|
return ResolvableType.forInstance(value);
|
||||||
}
|
}
|
||||||
|
@ -153,9 +151,7 @@ class ConstructorOrFactoryMethodResolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private Method resolveFactoryMethod(BeanDefinition beanDefinition,
|
private Method resolveFactoryMethod(BeanDefinition beanDefinition, List<ResolvableType> valueTypes) {
|
||||||
List<ResolvableType> valueTypes) {
|
|
||||||
|
|
||||||
if (beanDefinition instanceof RootBeanDefinition rbd) {
|
if (beanDefinition instanceof RootBeanDefinition rbd) {
|
||||||
Method resolvedFactoryMethod = rbd.getResolvedFactoryMethod();
|
Method resolvedFactoryMethod = rbd.getResolvedFactoryMethod();
|
||||||
if (resolvedFactoryMethod != null) {
|
if (resolvedFactoryMethod != null) {
|
||||||
|
@ -165,15 +161,13 @@ class ConstructorOrFactoryMethodResolver {
|
||||||
String factoryMethodName = beanDefinition.getFactoryMethodName();
|
String factoryMethodName = beanDefinition.getFactoryMethodName();
|
||||||
if (factoryMethodName != null) {
|
if (factoryMethodName != null) {
|
||||||
String factoryBeanName = beanDefinition.getFactoryBeanName();
|
String factoryBeanName = beanDefinition.getFactoryBeanName();
|
||||||
Class<?> beanClass = getBeanClass((factoryBeanName != null)
|
Class<?> beanClass = getBeanClass(factoryBeanName != null ?
|
||||||
? this.beanFactory.getMergedBeanDefinition(factoryBeanName)
|
this.beanFactory.getMergedBeanDefinition(factoryBeanName) : beanDefinition);
|
||||||
: beanDefinition);
|
|
||||||
List<Method> methods = new ArrayList<>();
|
List<Method> methods = new ArrayList<>();
|
||||||
Assert.state(beanClass != null,
|
Assert.state(beanClass != null,
|
||||||
() -> "Failed to determine bean class of " + beanDefinition);
|
() -> "Failed to determine bean class of " + beanDefinition);
|
||||||
ReflectionUtils.doWithMethods(beanClass, methods::add,
|
ReflectionUtils.doWithMethods(beanClass, methods::add,
|
||||||
method -> isFactoryMethodCandidate(beanClass, method,
|
method -> isFactoryMethodCandidate(beanClass, method, factoryMethodName));
|
||||||
factoryMethodName));
|
|
||||||
if (methods.size() >= 1) {
|
if (methods.size() >= 1) {
|
||||||
Function<Method, List<ResolvableType>> parameterTypesFactory = method -> {
|
Function<Method, List<ResolvableType>> parameterTypesFactory = method -> {
|
||||||
List<ResolvableType> types = new ArrayList<>();
|
List<ResolvableType> types = new ArrayList<>();
|
||||||
|
@ -182,16 +176,13 @@ class ConstructorOrFactoryMethodResolver {
|
||||||
}
|
}
|
||||||
return types;
|
return types;
|
||||||
};
|
};
|
||||||
return (Method) resolveFactoryMethod(methods, parameterTypesFactory,
|
return (Method) resolveFactoryMethod(methods, parameterTypesFactory, valueTypes);
|
||||||
valueTypes);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isFactoryMethodCandidate(Class<?> beanClass, Method method,
|
private boolean isFactoryMethodCandidate(Class<?> beanClass, Method method, String factoryMethodName) {
|
||||||
String factoryMethodName) {
|
|
||||||
|
|
||||||
if (method.getName().equals(factoryMethodName)) {
|
if (method.getName().equals(factoryMethodName)) {
|
||||||
if (Modifier.isStatic(method.getModifiers())) {
|
if (Modifier.isStatic(method.getModifiers())) {
|
||||||
return method.getDeclaringClass().equals(beanClass);
|
return method.getDeclaringClass().equals(beanClass);
|
||||||
|
@ -202,9 +193,7 @@ class ConstructorOrFactoryMethodResolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private Executable resolveConstructor(Supplier<ResolvableType> beanType,
|
private Executable resolveConstructor(Supplier<ResolvableType> beanType, List<ResolvableType> valueTypes) {
|
||||||
List<ResolvableType> valueTypes) {
|
|
||||||
|
|
||||||
Class<?> type = ClassUtils.getUserClass(beanType.get().toClass());
|
Class<?> type = ClassUtils.getUserClass(beanType.get().toClass());
|
||||||
Constructor<?>[] constructors = type.getDeclaredConstructors();
|
Constructor<?>[] constructors = type.getDeclaredConstructors();
|
||||||
if (constructors.length == 1) {
|
if (constructors.length == 1) {
|
||||||
|
@ -240,47 +229,41 @@ class ConstructorOrFactoryMethodResolver {
|
||||||
List<? extends Executable> typeConversionFallbackMatches = Arrays
|
List<? extends Executable> typeConversionFallbackMatches = Arrays
|
||||||
.stream(constructors)
|
.stream(constructors)
|
||||||
.filter(executable -> match(parameterTypesFactory.apply(executable),
|
.filter(executable -> match(parameterTypesFactory.apply(executable),
|
||||||
valueTypes,
|
valueTypes, FallbackMode.TYPE_CONVERSION))
|
||||||
ConstructorOrFactoryMethodResolver.FallbackMode.TYPE_CONVERSION))
|
|
||||||
.toList();
|
.toList();
|
||||||
return (typeConversionFallbackMatches.size() == 1)
|
return (typeConversionFallbackMatches.size() == 1)
|
||||||
? typeConversionFallbackMatches.get(0) : null;
|
? typeConversionFallbackMatches.get(0) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
private Executable resolveFactoryMethod(List<Method> executables,
|
private Executable resolveFactoryMethod(List<Method> executables,
|
||||||
Function<Method, List<ResolvableType>> parameterTypesFactory,
|
Function<Method, List<ResolvableType>> parameterTypesFactory,
|
||||||
List<ResolvableType> valueTypes) {
|
List<ResolvableType> valueTypes) {
|
||||||
|
|
||||||
List<? extends Executable> matches = executables.stream()
|
List<? extends Executable> matches = executables.stream()
|
||||||
.filter(executable -> match(parameterTypesFactory.apply(executable),
|
.filter(executable -> match(parameterTypesFactory.apply(executable), valueTypes, FallbackMode.NONE))
|
||||||
valueTypes, ConstructorOrFactoryMethodResolver.FallbackMode.NONE))
|
|
||||||
.toList();
|
.toList();
|
||||||
if (matches.size() == 1) {
|
if (matches.size() == 1) {
|
||||||
return matches.get(0);
|
return matches.get(0);
|
||||||
}
|
}
|
||||||
List<? extends Executable> assignableElementFallbackMatches = executables.stream()
|
List<? extends Executable> assignableElementFallbackMatches = executables.stream()
|
||||||
.filter(executable -> match(parameterTypesFactory.apply(executable),
|
.filter(executable -> match(parameterTypesFactory.apply(executable),
|
||||||
valueTypes,
|
valueTypes, FallbackMode.ASSIGNABLE_ELEMENT))
|
||||||
ConstructorOrFactoryMethodResolver.FallbackMode.ASSIGNABLE_ELEMENT))
|
|
||||||
.toList();
|
.toList();
|
||||||
if (assignableElementFallbackMatches.size() == 1) {
|
if (assignableElementFallbackMatches.size() == 1) {
|
||||||
return assignableElementFallbackMatches.get(0);
|
return assignableElementFallbackMatches.get(0);
|
||||||
}
|
}
|
||||||
List<? extends Executable> typeConversionFallbackMatches = executables.stream()
|
List<? extends Executable> typeConversionFallbackMatches = executables.stream()
|
||||||
.filter(executable -> match(parameterTypesFactory.apply(executable),
|
.filter(executable -> match(parameterTypesFactory.apply(executable),
|
||||||
valueTypes,
|
valueTypes, FallbackMode.TYPE_CONVERSION))
|
||||||
ConstructorOrFactoryMethodResolver.FallbackMode.TYPE_CONVERSION))
|
|
||||||
.toList();
|
.toList();
|
||||||
Assert.state(typeConversionFallbackMatches.size() <= 1,
|
Assert.state(typeConversionFallbackMatches.size() <= 1,
|
||||||
() -> "Multiple matches with parameters '" + valueTypes + "': "
|
() -> "Multiple matches with parameters '" + valueTypes + "': " + typeConversionFallbackMatches);
|
||||||
+ typeConversionFallbackMatches);
|
return (typeConversionFallbackMatches.size() == 1 ? typeConversionFallbackMatches.get(0) : null);
|
||||||
return (typeConversionFallbackMatches.size() == 1)
|
|
||||||
? typeConversionFallbackMatches.get(0) : null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean match(List<ResolvableType> parameterTypes,
|
private boolean match(
|
||||||
List<ResolvableType> valueTypes,
|
List<ResolvableType> parameterTypes, List<ResolvableType> valueTypes, FallbackMode fallbackMode) {
|
||||||
ConstructorOrFactoryMethodResolver.FallbackMode fallbackMode) {
|
|
||||||
|
|
||||||
if (parameterTypes.size() != valueTypes.size()) {
|
if (parameterTypes.size() != valueTypes.size()) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -293,15 +276,12 @@ class ConstructorOrFactoryMethodResolver {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isMatch(ResolvableType parameterType, ResolvableType valueType,
|
private boolean isMatch(ResolvableType parameterType, ResolvableType valueType, FallbackMode fallbackMode) {
|
||||||
ConstructorOrFactoryMethodResolver.FallbackMode fallbackMode) {
|
|
||||||
|
|
||||||
if (isAssignable(valueType).test(parameterType)) {
|
if (isAssignable(valueType).test(parameterType)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return switch (fallbackMode) {
|
return switch (fallbackMode) {
|
||||||
case ASSIGNABLE_ELEMENT -> isAssignable(valueType)
|
case ASSIGNABLE_ELEMENT -> isAssignable(valueType).test(extractElementType(parameterType));
|
||||||
.test(extractElementType(parameterType));
|
|
||||||
case TYPE_CONVERSION -> typeConversionFallback(valueType).test(parameterType);
|
case TYPE_CONVERSION -> typeConversionFallback(valueType).test(parameterType);
|
||||||
default -> false;
|
default -> false;
|
||||||
};
|
};
|
||||||
|
@ -323,12 +303,10 @@ class ConstructorOrFactoryMethodResolver {
|
||||||
|
|
||||||
private Predicate<ResolvableType> typeConversionFallback(ResolvableType valueType) {
|
private Predicate<ResolvableType> typeConversionFallback(ResolvableType valueType) {
|
||||||
return parameterType -> {
|
return parameterType -> {
|
||||||
if (valueOrCollection(valueType, this::isStringForClassFallback)
|
if (valueOrCollection(valueType, this::isStringForClassFallback).test(parameterType)) {
|
||||||
.test(parameterType)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return valueOrCollection(valueType, this::isSimpleConvertibleType)
|
return valueOrCollection(valueType, this::isSimpleValueType).test(parameterType);
|
||||||
.test(parameterType);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,12 +317,10 @@ class ConstructorOrFactoryMethodResolver {
|
||||||
if (predicateProvider.apply(valueType).test(parameterType)) {
|
if (predicateProvider.apply(valueType).test(parameterType)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (predicateProvider.apply(extractElementType(valueType))
|
if (predicateProvider.apply(extractElementType(valueType)).test(extractElementType(parameterType))) {
|
||||||
.test(extractElementType(parameterType))) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return (predicateProvider.apply(valueType)
|
return (predicateProvider.apply(valueType).test(extractElementType(parameterType)));
|
||||||
.test(extractElementType(parameterType)));
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -358,13 +334,13 @@ class ConstructorOrFactoryMethodResolver {
|
||||||
* parameter
|
* parameter
|
||||||
*/
|
*/
|
||||||
private Predicate<ResolvableType> isStringForClassFallback(ResolvableType valueType) {
|
private Predicate<ResolvableType> isStringForClassFallback(ResolvableType valueType) {
|
||||||
return parameterType -> (valueType.isAssignableFrom(String.class)
|
return parameterType -> (valueType.isAssignableFrom(String.class) &&
|
||||||
&& parameterType.isAssignableFrom(Class.class));
|
parameterType.isAssignableFrom(Class.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Predicate<ResolvableType> isSimpleConvertibleType(ResolvableType valueType) {
|
private Predicate<ResolvableType> isSimpleValueType(ResolvableType valueType) {
|
||||||
return parameterType -> isSimpleConvertibleType(parameterType.toClass())
|
return parameterType -> (BeanUtils.isSimpleValueType(parameterType.toClass()) &&
|
||||||
&& isSimpleConvertibleType(valueType.toClass());
|
BeanUtils.isSimpleValueType(valueType.toClass()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@ -372,7 +348,7 @@ class ConstructorOrFactoryMethodResolver {
|
||||||
if (beanDefinition instanceof RootBeanDefinition rbd) {
|
if (beanDefinition instanceof RootBeanDefinition rbd) {
|
||||||
if (rbd.hasBeanClass()) {
|
if (rbd.hasBeanClass()) {
|
||||||
Class<?> beanClass = rbd.getBeanClass();
|
Class<?> beanClass = rbd.getBeanClass();
|
||||||
return FactoryBean.class.isAssignableFrom(beanClass) ? beanClass : null;
|
return (FactoryBean.class.isAssignableFrom(beanClass) ? beanClass : null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -380,12 +356,10 @@ class ConstructorOrFactoryMethodResolver {
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private Class<?> getBeanClass(BeanDefinition beanDefinition) {
|
private Class<?> getBeanClass(BeanDefinition beanDefinition) {
|
||||||
if (beanDefinition instanceof AbstractBeanDefinition abd) {
|
if (beanDefinition instanceof AbstractBeanDefinition abd && abd.hasBeanClass()) {
|
||||||
return abd.hasBeanClass() ? abd.getBeanClass()
|
return abd.getBeanClass();
|
||||||
: loadClass(abd.getBeanClassName());
|
|
||||||
}
|
}
|
||||||
return (beanDefinition.getBeanClassName() != null)
|
return (beanDefinition.getBeanClassName() != null ? loadClass(beanDefinition.getBeanClassName()) : null);
|
||||||
? loadClass(beanDefinition.getBeanClassName()) : null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ResolvableType getBeanType(BeanDefinition beanDefinition) {
|
private ResolvableType getBeanType(BeanDefinition beanDefinition) {
|
||||||
|
@ -416,21 +390,6 @@ class ConstructorOrFactoryMethodResolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private <T> T getField(BeanDefinition beanDefinition, String fieldName,
|
|
||||||
Class<T> targetType) {
|
|
||||||
|
|
||||||
Field field = ReflectionUtils.findField(RootBeanDefinition.class, fieldName);
|
|
||||||
ReflectionUtils.makeAccessible(field);
|
|
||||||
return targetType.cast(ReflectionUtils.getField(field, beanDefinition));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isSimpleConvertibleType(Class<?> type) {
|
|
||||||
return (type.isPrimitive() && type != void.class) || type == Double.class
|
|
||||||
|| type == Float.class || type == Long.class || type == Integer.class
|
|
||||||
|| type == Short.class || type == Character.class || type == Byte.class
|
|
||||||
|| type == Boolean.class || type == String.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Executable resolve(RegisteredBean registeredBean) {
|
static Executable resolve(RegisteredBean registeredBean) {
|
||||||
return new ConstructorOrFactoryMethodResolver(registeredBean.getBeanFactory())
|
return new ConstructorOrFactoryMethodResolver(registeredBean.getBeanFactory())
|
||||||
.resolve(registeredBean.getMergedBeanDefinition());
|
.resolve(registeredBean.getMergedBeanDefinition());
|
||||||
|
@ -444,7 +403,6 @@ class ConstructorOrFactoryMethodResolver {
|
||||||
ASSIGNABLE_ELEMENT,
|
ASSIGNABLE_ELEMENT,
|
||||||
|
|
||||||
TYPE_CONVERSION
|
TYPE_CONVERSION
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,8 +141,7 @@ class ConstructorOrFactoryMethodResolverTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void beanDefinitionWithMultiArgConstructorAndMatchingValue()
|
void beanDefinitionWithMultiArgConstructorAndMatchingValue() throws NoSuchMethodException {
|
||||||
throws NoSuchMethodException {
|
|
||||||
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
||||||
.rootBeanDefinition(MultiConstructorSample.class)
|
.rootBeanDefinition(MultiConstructorSample.class)
|
||||||
.addConstructorArgValue(42).getBeanDefinition();
|
.addConstructorArgValue(42).getBeanDefinition();
|
||||||
|
@ -152,8 +151,7 @@ class ConstructorOrFactoryMethodResolverTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void beanDefinitionWithMultiArgConstructorAndMatchingArrayValue()
|
void beanDefinitionWithMultiArgConstructorAndMatchingArrayValue() throws NoSuchMethodException {
|
||||||
throws NoSuchMethodException {
|
|
||||||
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
||||||
.rootBeanDefinition(MultiConstructorArraySample.class)
|
.rootBeanDefinition(MultiConstructorArraySample.class)
|
||||||
.addConstructorArgValue(42).getBeanDefinition();
|
.addConstructorArgValue(42).getBeanDefinition();
|
||||||
|
@ -163,8 +161,7 @@ class ConstructorOrFactoryMethodResolverTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void beanDefinitionWithMultiArgConstructorAndMatchingListValue()
|
void beanDefinitionWithMultiArgConstructorAndMatchingListValue() throws NoSuchMethodException {
|
||||||
throws NoSuchMethodException {
|
|
||||||
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
||||||
.rootBeanDefinition(MultiConstructorListSample.class)
|
.rootBeanDefinition(MultiConstructorListSample.class)
|
||||||
.addConstructorArgValue(42).getBeanDefinition();
|
.addConstructorArgValue(42).getBeanDefinition();
|
||||||
|
@ -174,8 +171,7 @@ class ConstructorOrFactoryMethodResolverTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void beanDefinitionWithMultiArgConstructorAndMatchingValueAsInnerBean()
|
void beanDefinitionWithMultiArgConstructorAndMatchingValueAsInnerBean() throws NoSuchMethodException {
|
||||||
throws NoSuchMethodException {
|
|
||||||
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
||||||
.rootBeanDefinition(MultiConstructorSample.class)
|
.rootBeanDefinition(MultiConstructorSample.class)
|
||||||
.addConstructorArgValue(
|
.addConstructorArgValue(
|
||||||
|
@ -188,8 +184,7 @@ class ConstructorOrFactoryMethodResolverTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void beanDefinitionWithMultiArgConstructorAndMatchingValueAsInnerBeanFactory()
|
void beanDefinitionWithMultiArgConstructorAndMatchingValueAsInnerBeanFactory() throws NoSuchMethodException {
|
||||||
throws NoSuchMethodException {
|
|
||||||
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
||||||
.rootBeanDefinition(MultiConstructorSample.class)
|
.rootBeanDefinition(MultiConstructorSample.class)
|
||||||
.addConstructorArgValue(BeanDefinitionBuilder
|
.addConstructorArgValue(BeanDefinitionBuilder
|
||||||
|
@ -258,8 +253,7 @@ class ConstructorOrFactoryMethodResolverTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void beanDefinitionWithClassArrayConstructorArgAndStringArrayValueType()
|
void beanDefinitionWithClassArrayConstructorArgAndStringArrayValueType() throws NoSuchMethodException {
|
||||||
throws NoSuchMethodException {
|
|
||||||
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
||||||
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
||||||
.rootBeanDefinition(ConstructorClassArraySample.class.getName())
|
.rootBeanDefinition(ConstructorClassArraySample.class.getName())
|
||||||
|
@ -282,8 +276,7 @@ class ConstructorOrFactoryMethodResolverTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void beanDefinitionWithClassArrayConstructorArgAndAnotherMatchingConstructor()
|
void beanDefinitionWithClassArrayConstructorArgAndAnotherMatchingConstructor() throws NoSuchMethodException {
|
||||||
throws NoSuchMethodException {
|
|
||||||
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
||||||
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
||||||
.rootBeanDefinition(MultiConstructorClassArraySample.class.getName())
|
.rootBeanDefinition(MultiConstructorClassArraySample.class.getName())
|
||||||
|
@ -323,8 +316,7 @@ class ConstructorOrFactoryMethodResolverTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void beanDefinitionWithMultiArgConstructorAndPrimitiveConversion()
|
void beanDefinitionWithMultiArgConstructorAndPrimitiveConversion() throws NoSuchMethodException {
|
||||||
throws NoSuchMethodException {
|
|
||||||
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
||||||
.rootBeanDefinition(ConstructorPrimitiveFallback.class)
|
.rootBeanDefinition(ConstructorPrimitiveFallback.class)
|
||||||
.addConstructorArgValue("true").getBeanDefinition();
|
.addConstructorArgValue("true").getBeanDefinition();
|
||||||
|
@ -345,12 +337,13 @@ class ConstructorOrFactoryMethodResolverTests {
|
||||||
Class.class));
|
Class.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Executable resolve(DefaultListableBeanFactory beanFactory,
|
|
||||||
BeanDefinition beanDefinition) {
|
@Nullable
|
||||||
return new ConstructorOrFactoryMethodResolver(beanFactory)
|
private Executable resolve(DefaultListableBeanFactory beanFactory, BeanDefinition beanDefinition) {
|
||||||
.resolve(beanDefinition);
|
return new ConstructorOrFactoryMethodResolver(beanFactory).resolve(beanDefinition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static class IntegerFactoryBean implements FactoryBean<Integer> {
|
static class IntegerFactoryBean implements FactoryBean<Integer> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -372,7 +365,6 @@ class ConstructorOrFactoryMethodResolverTests {
|
||||||
|
|
||||||
MultiConstructorSample(Integer value) {
|
MultiConstructorSample(Integer value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
|
@ -393,7 +385,6 @@ class ConstructorOrFactoryMethodResolverTests {
|
||||||
|
|
||||||
public MultiConstructorListSample(List<Integer> values) {
|
public MultiConstructorListSample(List<Integer> values) {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DummyInterface {
|
interface DummyInterface {
|
||||||
|
@ -441,7 +432,6 @@ class ConstructorOrFactoryMethodResolverTests {
|
||||||
static String of(Class<?>[] classArrayArg) {
|
static String of(Class<?>[] classArrayArg) {
|
||||||
return "test";
|
return "test";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
|
@ -454,7 +444,6 @@ class ConstructorOrFactoryMethodResolverTests {
|
||||||
static String of(String[] classArrayArg) {
|
static String of(String[] classArrayArg) {
|
||||||
return "test";
|
return "test";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unnused")
|
@SuppressWarnings("unnused")
|
||||||
|
@ -465,7 +454,6 @@ class ConstructorOrFactoryMethodResolverTests {
|
||||||
|
|
||||||
public ConstructorPrimitiveFallback(Executor executor) {
|
public ConstructorPrimitiveFallback(Executor executor) {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static class SampleBeanWithConstructors {
|
static class SampleBeanWithConstructors {
|
||||||
|
@ -478,7 +466,6 @@ class ConstructorOrFactoryMethodResolverTests {
|
||||||
|
|
||||||
public SampleBeanWithConstructors(Number number, String name) {
|
public SampleBeanWithConstructors(Number number, String name) {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface FactoryWithOverloadedClassMethodsOnInterface {
|
interface FactoryWithOverloadedClassMethodsOnInterface {
|
||||||
|
@ -493,7 +480,6 @@ class ConstructorOrFactoryMethodResolverTests {
|
||||||
SearchStrategy searchStrategy) {
|
SearchStrategy searchStrategy) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue