Merge branch '6.0.x'
This commit is contained in:
commit
351a200747
|
@ -705,7 +705,7 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
|
|||
private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
|
||||
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
|
||||
desc.setContainingClass(bean.getClass());
|
||||
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
|
||||
Set<String> autowiredBeanNames = new LinkedHashSet<>(2);
|
||||
Assert.state(beanFactory != null, "No BeanFactory available");
|
||||
TypeConverter typeConverter = beanFactory.getTypeConverter();
|
||||
Object value;
|
||||
|
@ -724,8 +724,7 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
|
|||
String autowiredBeanName = autowiredBeanNames.iterator().next();
|
||||
if (beanFactory.containsBean(autowiredBeanName) &&
|
||||
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
|
||||
cachedFieldValue = new ShortcutDependencyDescriptor(
|
||||
desc, autowiredBeanName, field.getType());
|
||||
cachedFieldValue = new ShortcutDependencyDescriptor(desc, autowiredBeanName);
|
||||
}
|
||||
}
|
||||
this.cachedFieldValue = cachedFieldValue;
|
||||
|
@ -805,7 +804,7 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
|
|||
int argumentCount = method.getParameterCount();
|
||||
Object[] arguments = new Object[argumentCount];
|
||||
DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount];
|
||||
Set<String> autowiredBeans = new LinkedHashSet<>(argumentCount);
|
||||
Set<String> autowiredBeanNames = new LinkedHashSet<>(argumentCount * 2);
|
||||
Assert.state(beanFactory != null, "No BeanFactory available");
|
||||
TypeConverter typeConverter = beanFactory.getTypeConverter();
|
||||
for (int i = 0; i < arguments.length; i++) {
|
||||
|
@ -814,7 +813,7 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
|
|||
currDesc.setContainingClass(bean.getClass());
|
||||
descriptors[i] = currDesc;
|
||||
try {
|
||||
Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
|
||||
Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeanNames, typeConverter);
|
||||
if (arg == null && !this.required) {
|
||||
arguments = null;
|
||||
break;
|
||||
|
@ -829,16 +828,16 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
|
|||
if (!this.cached) {
|
||||
if (arguments != null) {
|
||||
DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, argumentCount);
|
||||
registerDependentBeans(beanName, autowiredBeans);
|
||||
if (autowiredBeans.size() == argumentCount) {
|
||||
Iterator<String> it = autowiredBeans.iterator();
|
||||
registerDependentBeans(beanName, autowiredBeanNames);
|
||||
if (autowiredBeanNames.size() == argumentCount) {
|
||||
Iterator<String> it = autowiredBeanNames.iterator();
|
||||
Class<?>[] paramTypes = method.getParameterTypes();
|
||||
for (int i = 0; i < paramTypes.length; i++) {
|
||||
String autowiredBeanName = it.next();
|
||||
if (arguments[i] != null && beanFactory.containsBean(autowiredBeanName) &&
|
||||
beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
|
||||
cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
|
||||
descriptors[i], autowiredBeanName, paramTypes[i]);
|
||||
descriptors[i], autowiredBeanName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -864,17 +863,14 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
|
|||
|
||||
private final String shortcut;
|
||||
|
||||
private final Class<?> requiredType;
|
||||
|
||||
public ShortcutDependencyDescriptor(DependencyDescriptor original, String shortcut, Class<?> requiredType) {
|
||||
public ShortcutDependencyDescriptor(DependencyDescriptor original, String shortcut) {
|
||||
super(original);
|
||||
this.shortcut = shortcut;
|
||||
this.requiredType = requiredType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object resolveShortcut(BeanFactory beanFactory) {
|
||||
return beanFactory.getBean(this.shortcut, this.requiredType);
|
||||
return beanFactory.getBean(this.shortcut, getDependencyType());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2023 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.
|
||||
|
@ -62,20 +62,14 @@ abstract class AutowiredElementResolver {
|
|||
|
||||
private final String shortcut;
|
||||
|
||||
private final Class<?> requiredType;
|
||||
|
||||
|
||||
public ShortcutDependencyDescriptor(DependencyDescriptor original,
|
||||
String shortcut, Class<?> requiredType) {
|
||||
public ShortcutDependencyDescriptor(DependencyDescriptor original, String shortcut) {
|
||||
super(original);
|
||||
this.shortcut = shortcut;
|
||||
this.requiredType = requiredType;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object resolveShortcut(BeanFactory beanFactory) {
|
||||
return beanFactory.getBean(this.shortcut, this.requiredType);
|
||||
return beanFactory.getBean(this.shortcut, getDependencyType());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2023 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.
|
||||
|
@ -179,8 +179,7 @@ public final class AutowiredFieldValueResolver extends AutowiredElementResolver
|
|||
DependencyDescriptor descriptor = new DependencyDescriptor(field, this.required);
|
||||
descriptor.setContainingClass(beanClass);
|
||||
if (this.shortcut != null) {
|
||||
descriptor = new ShortcutDependencyDescriptor(descriptor, this.shortcut,
|
||||
field.getType());
|
||||
descriptor = new ShortcutDependencyDescriptor(descriptor, this.shortcut);
|
||||
}
|
||||
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
|
||||
TypeConverter typeConverter = beanFactory.getTypeConverter();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2023 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.
|
||||
|
@ -76,6 +76,7 @@ public final class AutowiredMethodArgumentsResolver extends AutowiredElementReso
|
|||
this.shortcuts = shortcuts;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new {@link AutowiredMethodArgumentsResolver} for the specified
|
||||
* method where injection is optional.
|
||||
|
@ -83,11 +84,8 @@ public final class AutowiredMethodArgumentsResolver extends AutowiredElementReso
|
|||
* @param parameterTypes the factory method parameter types
|
||||
* @return a new {@link AutowiredFieldValueResolver} instance
|
||||
*/
|
||||
public static AutowiredMethodArgumentsResolver forMethod(String methodName,
|
||||
Class<?>... parameterTypes) {
|
||||
|
||||
return new AutowiredMethodArgumentsResolver(methodName, parameterTypes, false,
|
||||
null);
|
||||
public static AutowiredMethodArgumentsResolver forMethod(String methodName, Class<?>... parameterTypes) {
|
||||
return new AutowiredMethodArgumentsResolver(methodName, parameterTypes, false, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -97,11 +95,8 @@ public final class AutowiredMethodArgumentsResolver extends AutowiredElementReso
|
|||
* @param parameterTypes the factory method parameter types
|
||||
* @return a new {@link AutowiredFieldValueResolver} instance
|
||||
*/
|
||||
public static AutowiredMethodArgumentsResolver forRequiredMethod(String methodName,
|
||||
Class<?>... parameterTypes) {
|
||||
|
||||
return new AutowiredMethodArgumentsResolver(methodName, parameterTypes, true,
|
||||
null);
|
||||
public static AutowiredMethodArgumentsResolver forRequiredMethod(String methodName, Class<?>... parameterTypes) {
|
||||
return new AutowiredMethodArgumentsResolver(methodName, parameterTypes, true, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -113,8 +108,7 @@ public final class AutowiredMethodArgumentsResolver extends AutowiredElementReso
|
|||
* the shortcuts
|
||||
*/
|
||||
public AutowiredMethodArgumentsResolver withShortcut(String... beanNames) {
|
||||
return new AutowiredMethodArgumentsResolver(this.methodName, this.parameterTypes,
|
||||
this.required, beanNames);
|
||||
return new AutowiredMethodArgumentsResolver(this.methodName, this.parameterTypes, this.required, beanNames);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -123,9 +117,7 @@ public final class AutowiredMethodArgumentsResolver extends AutowiredElementReso
|
|||
* @param registeredBean the registered bean
|
||||
* @param action the action to execute with the resolved method arguments
|
||||
*/
|
||||
public void resolve(RegisteredBean registeredBean,
|
||||
ThrowingConsumer<AutowiredArguments> action) {
|
||||
|
||||
public void resolve(RegisteredBean registeredBean, ThrowingConsumer<AutowiredArguments> action) {
|
||||
Assert.notNull(registeredBean, "'registeredBean' must not be null");
|
||||
Assert.notNull(action, "'action' must not be null");
|
||||
AutowiredArguments resolved = resolve(registeredBean);
|
||||
|
@ -177,25 +169,22 @@ public final class AutowiredMethodArgumentsResolver extends AutowiredElementReso
|
|||
TypeConverter typeConverter = beanFactory.getTypeConverter();
|
||||
for (int i = 0; i < argumentCount; i++) {
|
||||
MethodParameter parameter = new MethodParameter(method, i);
|
||||
DependencyDescriptor descriptor = new DependencyDescriptor(parameter,
|
||||
this.required);
|
||||
DependencyDescriptor descriptor = new DependencyDescriptor(parameter, this.required);
|
||||
descriptor.setContainingClass(beanClass);
|
||||
String shortcut = (this.shortcuts != null) ? this.shortcuts[i] : null;
|
||||
String shortcut = (this.shortcuts != null ? this.shortcuts[i] : null);
|
||||
if (shortcut != null) {
|
||||
descriptor = new ShortcutDependencyDescriptor(descriptor, shortcut,
|
||||
parameter.getParameterType());
|
||||
descriptor = new ShortcutDependencyDescriptor(descriptor, shortcut);
|
||||
}
|
||||
try {
|
||||
Object argument = autowireCapableBeanFactory.resolveDependency(descriptor,
|
||||
beanName, autowiredBeanNames, typeConverter);
|
||||
Object argument = autowireCapableBeanFactory.resolveDependency(
|
||||
descriptor, beanName, autowiredBeanNames, typeConverter);
|
||||
if (argument == null && !this.required) {
|
||||
return null;
|
||||
}
|
||||
arguments[i] = argument;
|
||||
}
|
||||
catch (BeansException ex) {
|
||||
throw new UnsatisfiedDependencyException(null, beanName,
|
||||
new InjectionPoint(parameter), ex);
|
||||
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(parameter), ex);
|
||||
}
|
||||
}
|
||||
registerDependentBeans(beanFactory, beanName, autowiredBeanNames);
|
||||
|
|
|
@ -249,18 +249,18 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
|||
() -> "'shortcuts' must contain " + resolved.length + " elements");
|
||||
|
||||
ConstructorArgumentValues argumentValues = resolveArgumentValues(registeredBean);
|
||||
Set<String> autowiredBeans = new LinkedHashSet<>(resolved.length);
|
||||
Set<String> autowiredBeanNames = new LinkedHashSet<>(resolved.length * 2);
|
||||
for (int i = startIndex; i < parameterCount; i++) {
|
||||
MethodParameter parameter = getMethodParameter(executable, i);
|
||||
DependencyDescriptor descriptor = new DependencyDescriptor(parameter, true);
|
||||
String shortcut = (this.shortcuts != null ? this.shortcuts[i - startIndex] : null);
|
||||
if (shortcut != null) {
|
||||
descriptor = new ShortcutDependencyDescriptor(descriptor, shortcut, registeredBean.getBeanClass());
|
||||
descriptor = new ShortcutDependencyDescriptor(descriptor, shortcut);
|
||||
}
|
||||
ValueHolder argumentValue = argumentValues.getIndexedArgumentValue(i, null);
|
||||
resolved[i - startIndex] = resolveArgument(registeredBean, descriptor, argumentValue, autowiredBeans);
|
||||
resolved[i - startIndex] = resolveArgument(registeredBean, descriptor, argumentValue, autowiredBeanNames);
|
||||
}
|
||||
registerDependentBeans(registeredBean.getBeanFactory(), registeredBean.getBeanName(), autowiredBeans);
|
||||
registerDependentBeans(registeredBean.getBeanFactory(), registeredBean.getBeanName(), autowiredBeanNames);
|
||||
|
||||
return AutowiredArguments.of(resolved);
|
||||
}
|
||||
|
@ -303,7 +303,7 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
|||
|
||||
@Nullable
|
||||
private Object resolveArgument(RegisteredBean registeredBean, DependencyDescriptor descriptor,
|
||||
@Nullable ValueHolder argumentValue, Set<String> autowiredBeans) {
|
||||
@Nullable ValueHolder argumentValue, Set<String> autowiredBeanNames) {
|
||||
|
||||
TypeConverter typeConverter = registeredBean.getBeanFactory().getTypeConverter();
|
||||
if (argumentValue != null) {
|
||||
|
@ -312,7 +312,7 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
|||
descriptor.getDependencyType(), descriptor.getMethodParameter()));
|
||||
}
|
||||
try {
|
||||
return registeredBean.resolveAutowiredArgument(descriptor, typeConverter, autowiredBeans);
|
||||
return registeredBean.resolveAutowiredArgument(descriptor, typeConverter, autowiredBeanNames);
|
||||
}
|
||||
catch (BeansException ex) {
|
||||
throw new UnsatisfiedDependencyException(null, registeredBean.getBeanName(), descriptor, ex);
|
||||
|
|
|
@ -1484,8 +1484,8 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
|||
converter = bw;
|
||||
}
|
||||
|
||||
Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
|
||||
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
|
||||
Set<String> autowiredBeanNames = new LinkedHashSet<>(propertyNames.length * 2);
|
||||
for (String propertyName : propertyNames) {
|
||||
try {
|
||||
PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
|
||||
|
|
|
@ -153,7 +153,7 @@ public class BeanDefinitionValueResolver {
|
|||
(name, mbd) -> resolveInnerBeanValue(argName, name, mbd));
|
||||
}
|
||||
else if (value instanceof DependencyDescriptor dependencyDescriptor) {
|
||||
Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
|
||||
Set<String> autowiredBeanNames = new LinkedHashSet<>(2);
|
||||
Object result = this.beanFactory.resolveDependency(
|
||||
dependencyDescriptor, this.beanName, autowiredBeanNames, this.typeConverter);
|
||||
for (String autowiredBeanName : autowiredBeanNames) {
|
||||
|
|
|
@ -48,6 +48,7 @@ import org.springframework.beans.TypeConverter;
|
|||
import org.springframework.beans.TypeMismatchException;
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InjectionPoint;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
|
@ -85,7 +86,7 @@ import org.springframework.util.StringUtils;
|
|||
* @author Sebastien Deleuze
|
||||
* @author Sam Brannen
|
||||
* @author Stephane Nicoll
|
||||
* @author Phil Webb
|
||||
* @author Phillip Webb
|
||||
* @since 2.0
|
||||
* @see #autowireConstructor
|
||||
* @see #instantiateUsingFactoryMethod
|
||||
|
@ -96,12 +97,6 @@ class ConstructorResolver {
|
|||
|
||||
private static final Object[] EMPTY_ARGS = new Object[0];
|
||||
|
||||
/**
|
||||
* Marker for autowired arguments in a cached argument array, to be replaced
|
||||
* by a {@linkplain #resolveAutowiredArgument resolved autowired argument}.
|
||||
*/
|
||||
private static final Object autowiredArgumentMarker = new Object();
|
||||
|
||||
private static final NamedThreadLocal<InjectionPoint> currentInjectionPoint =
|
||||
new NamedThreadLocal<>("Current injection point");
|
||||
|
||||
|
@ -729,7 +724,7 @@ class ConstructorResolver {
|
|||
|
||||
ArgumentsHolder args = new ArgumentsHolder(paramTypes.length);
|
||||
Set<ConstructorArgumentValues.ValueHolder> usedValueHolders = new HashSet<>(paramTypes.length);
|
||||
Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
|
||||
Set<String> allAutowiredBeanNames = new LinkedHashSet<>(paramTypes.length * 2);
|
||||
|
||||
for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {
|
||||
Class<?> paramType = paramTypes[paramIndex];
|
||||
|
@ -764,8 +759,8 @@ class ConstructorResolver {
|
|||
throw new UnsatisfiedDependencyException(
|
||||
mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),
|
||||
"Could not convert argument value of type [" +
|
||||
ObjectUtils.nullSafeClassName(valueHolder.getValue()) +
|
||||
"] to required type [" + paramType.getName() + "]: " + ex.getMessage());
|
||||
ObjectUtils.nullSafeClassName(valueHolder.getValue()) +
|
||||
"] to required type [" + paramType.getName() + "]: " + ex.getMessage());
|
||||
}
|
||||
Object sourceHolder = valueHolder.getSource();
|
||||
if (sourceHolder instanceof ConstructorArgumentValues.ValueHolder constructorValueHolder) {
|
||||
|
@ -788,11 +783,17 @@ class ConstructorResolver {
|
|||
"] - did you specify the correct bean references as arguments?");
|
||||
}
|
||||
try {
|
||||
Object autowiredArgument = resolveAutowiredArgument(new DependencyDescriptor(methodParam, true),
|
||||
beanName, autowiredBeanNames, converter, fallback);
|
||||
args.rawArguments[paramIndex] = autowiredArgument;
|
||||
args.arguments[paramIndex] = autowiredArgument;
|
||||
args.preparedArguments[paramIndex] = autowiredArgumentMarker;
|
||||
ConstructorDependencyDescriptor desc = new ConstructorDependencyDescriptor(methodParam, true);
|
||||
Set<String> autowiredBeanNames = new LinkedHashSet<>(2);
|
||||
Object arg = resolveAutowiredArgument(
|
||||
desc, paramType, beanName, autowiredBeanNames, converter, fallback);
|
||||
if (arg != null) {
|
||||
setShortcutIfPossible(desc, paramType, autowiredBeanNames);
|
||||
}
|
||||
allAutowiredBeanNames.addAll(autowiredBeanNames);
|
||||
args.rawArguments[paramIndex] = arg;
|
||||
args.arguments[paramIndex] = arg;
|
||||
args.preparedArguments[paramIndex] = desc;
|
||||
args.resolveNecessary = true;
|
||||
}
|
||||
catch (BeansException ex) {
|
||||
|
@ -802,14 +803,7 @@ class ConstructorResolver {
|
|||
}
|
||||
}
|
||||
|
||||
for (String autowiredBeanName : autowiredBeanNames) {
|
||||
this.beanFactory.registerDependentBean(autowiredBeanName, beanName);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Autowiring by type from bean name '" + beanName +
|
||||
"' via " + (executable instanceof Constructor ? "constructor" : "factory method") +
|
||||
" to bean named '" + autowiredBeanName + "'");
|
||||
}
|
||||
}
|
||||
registerDependentBeans(executable, beanName, allAutowiredBeanNames);
|
||||
|
||||
return args;
|
||||
}
|
||||
|
@ -829,32 +823,56 @@ class ConstructorResolver {
|
|||
Object[] resolvedArgs = new Object[argsToResolve.length];
|
||||
for (int argIndex = 0; argIndex < argsToResolve.length; argIndex++) {
|
||||
Object argValue = argsToResolve[argIndex];
|
||||
MethodParameter methodParam = MethodParameter.forExecutable(executable, argIndex);
|
||||
if (argValue == autowiredArgumentMarker) {
|
||||
argValue = resolveAutowiredArgument(new DependencyDescriptor(methodParam, true),
|
||||
beanName, null, converter, true);
|
||||
Class<?> paramType = paramTypes[argIndex];
|
||||
boolean convertNecessary = false;
|
||||
if (argValue instanceof ConstructorDependencyDescriptor descriptor) {
|
||||
try {
|
||||
argValue = resolveAutowiredArgument(descriptor, paramType, beanName,
|
||||
null, converter, true);
|
||||
}
|
||||
catch (BeansException ex) {
|
||||
// Unexpected target bean mismatch for cached argument -> re-resolve
|
||||
synchronized (descriptor) {
|
||||
if (!descriptor.hasShortcut()) {
|
||||
throw ex;
|
||||
}
|
||||
descriptor.setShortcut(null);
|
||||
Set<String> autowiredBeanNames = new LinkedHashSet<>(2);
|
||||
argValue = resolveAutowiredArgument(descriptor, paramType, beanName,
|
||||
autowiredBeanNames, converter, true);
|
||||
if (argValue != null) {
|
||||
setShortcutIfPossible(descriptor, paramType, autowiredBeanNames);
|
||||
}
|
||||
registerDependentBeans(executable, beanName, autowiredBeanNames);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (argValue instanceof BeanMetadataElement) {
|
||||
argValue = valueResolver.resolveValueIfNecessary("constructor argument", argValue);
|
||||
convertNecessary = true;
|
||||
}
|
||||
else if (argValue instanceof String text) {
|
||||
argValue = this.beanFactory.evaluateBeanDefinitionString(text, mbd);
|
||||
convertNecessary = true;
|
||||
}
|
||||
Class<?> paramType = paramTypes[argIndex];
|
||||
try {
|
||||
resolvedArgs[argIndex] = converter.convertIfNecessary(argValue, paramType, methodParam);
|
||||
}
|
||||
catch (TypeMismatchException ex) {
|
||||
throw new UnsatisfiedDependencyException(
|
||||
mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),
|
||||
"Could not convert argument value of type [" + ObjectUtils.nullSafeClassName(argValue) +
|
||||
"] to required type [" + paramType.getName() + "]: " + ex.getMessage());
|
||||
if (convertNecessary) {
|
||||
MethodParameter methodParam = MethodParameter.forExecutable(executable, argIndex);
|
||||
try {
|
||||
argValue = converter.convertIfNecessary(argValue, paramType, methodParam);
|
||||
}
|
||||
catch (TypeMismatchException ex) {
|
||||
throw new UnsatisfiedDependencyException(
|
||||
mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),
|
||||
"Could not convert argument value of type [" + ObjectUtils.nullSafeClassName(argValue) +
|
||||
"] to required type [" + paramType.getName() + "]: " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
resolvedArgs[argIndex] = argValue;
|
||||
}
|
||||
return resolvedArgs;
|
||||
}
|
||||
|
||||
protected Constructor<?> getUserDeclaredConstructor(Constructor<?> constructor) {
|
||||
private Constructor<?> getUserDeclaredConstructor(Constructor<?> constructor) {
|
||||
Class<?> declaringClass = constructor.getDeclaringClass();
|
||||
Class<?> userClass = ClassUtils.getUserClass(declaringClass);
|
||||
if (userClass != declaringClass) {
|
||||
|
@ -870,13 +888,12 @@ class ConstructorResolver {
|
|||
}
|
||||
|
||||
/**
|
||||
* Template method for resolving the specified argument which is supposed to be autowired.
|
||||
* Resolve the specified argument which is supposed to be autowired.
|
||||
*/
|
||||
@Nullable
|
||||
protected Object resolveAutowiredArgument(DependencyDescriptor descriptor, String beanName,
|
||||
Object resolveAutowiredArgument(DependencyDescriptor descriptor, Class<?> paramType, String beanName,
|
||||
@Nullable Set<String> autowiredBeanNames, TypeConverter typeConverter, boolean fallback) {
|
||||
|
||||
Class<?> paramType = descriptor.getMethodParameter().getParameterType();
|
||||
if (InjectionPoint.class.isAssignableFrom(paramType)) {
|
||||
InjectionPoint injectionPoint = currentInjectionPoint.get();
|
||||
if (injectionPoint == null) {
|
||||
|
@ -884,9 +901,9 @@ class ConstructorResolver {
|
|||
}
|
||||
return injectionPoint;
|
||||
}
|
||||
|
||||
try {
|
||||
return this.beanFactory.resolveDependency(
|
||||
descriptor, beanName, autowiredBeanNames, typeConverter);
|
||||
return this.beanFactory.resolveDependency(descriptor, beanName, autowiredBeanNames, typeConverter);
|
||||
}
|
||||
catch (NoUniqueBeanDefinitionException ex) {
|
||||
throw ex;
|
||||
|
@ -909,6 +926,31 @@ class ConstructorResolver {
|
|||
}
|
||||
}
|
||||
|
||||
private void setShortcutIfPossible(
|
||||
ConstructorDependencyDescriptor descriptor, Class<?> paramType, Set<String> autowiredBeanNames) {
|
||||
|
||||
if (autowiredBeanNames.size() == 1) {
|
||||
String autowiredBeanName = autowiredBeanNames.iterator().next();
|
||||
if (this.beanFactory.containsBean(autowiredBeanName) &&
|
||||
this.beanFactory.isTypeMatch(autowiredBeanName, paramType)) {
|
||||
descriptor.setShortcut(autowiredBeanName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void registerDependentBeans(
|
||||
Executable executable, String beanName, Set<String> autowiredBeanNames) {
|
||||
|
||||
for (String autowiredBeanName : autowiredBeanNames) {
|
||||
this.beanFactory.registerDependentBean(autowiredBeanName, beanName);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Autowiring by type from bean name '" + beanName + "' via " +
|
||||
(executable instanceof Constructor ? "constructor" : "factory method") +
|
||||
" to bean named '" + autowiredBeanName + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// AOT-oriented pre-resolution
|
||||
|
||||
|
@ -1361,6 +1403,37 @@ class ConstructorResolver {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* DependencyDescriptor marker for constructor arguments,
|
||||
* for differentiating between a provided DependencyDescriptor instance
|
||||
* and an internally built DependencyDescriptor for autowiring purposes.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
private static class ConstructorDependencyDescriptor extends DependencyDescriptor {
|
||||
|
||||
@Nullable
|
||||
private volatile String shortcut;
|
||||
|
||||
public ConstructorDependencyDescriptor(MethodParameter methodParameter, boolean required) {
|
||||
super(methodParameter, required);
|
||||
}
|
||||
|
||||
public void setShortcut(@Nullable String shortcut) {
|
||||
this.shortcut = shortcut;
|
||||
}
|
||||
|
||||
public boolean hasShortcut() {
|
||||
return (this.shortcut != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object resolveShortcut(BeanFactory beanFactory) {
|
||||
String shortcut = this.shortcut;
|
||||
return (shortcut != null ? beanFactory.getBean(shortcut, getDependencyType()) : null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private enum FallbackMode {
|
||||
|
||||
NONE,
|
||||
|
|
|
@ -216,16 +216,18 @@ public final class RegisteredBean {
|
|||
* Resolve an autowired argument.
|
||||
* @param descriptor the descriptor for the dependency (field/method/constructor)
|
||||
* @param typeConverter the TypeConverter to use for populating arrays and collections
|
||||
* @param autowiredBeans a Set that all names of autowired beans (used for
|
||||
* @param autowiredBeanNames a Set that all names of autowired beans (used for
|
||||
* resolving the given dependency) are supposed to be added to
|
||||
* @return the resolved object, or {@code null} if none found
|
||||
* @since 6.0.9
|
||||
*/
|
||||
@Nullable
|
||||
public Object resolveAutowiredArgument(DependencyDescriptor descriptor, TypeConverter typeConverter,
|
||||
Set<String> autowiredBeans) {
|
||||
public Object resolveAutowiredArgument(
|
||||
DependencyDescriptor descriptor, TypeConverter typeConverter, Set<String> autowiredBeanNames) {
|
||||
|
||||
return new ConstructorResolver((AbstractAutowireCapableBeanFactory) getBeanFactory())
|
||||
.resolveAutowiredArgument(descriptor, getBeanName(), autowiredBeans, typeConverter, true);
|
||||
.resolveAutowiredArgument(descriptor, descriptor.getDependencyType(),
|
||||
getBeanName(), autowiredBeanNames, typeConverter, true);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -71,6 +71,8 @@ import org.springframework.core.ResolvableType;
|
|||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.testfixture.io.SerializationTestUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
@ -128,6 +130,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
|||
bean = bf.getBean("annotatedBean", ResourceInjectionBean.class);
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
|
||||
assertThat(bf.getDependenciesForBean("annotatedBean")).isEqualTo(new String[] {"testBean"});
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -150,10 +154,12 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
|||
assertThat(bean.getTestBean()).isNull();
|
||||
assertThat(bean.getTestBean2()).isNull();
|
||||
assertThat(bean.getTestBean3()).isNull();
|
||||
|
||||
assertThat(bf.getDependenciesForBean("annotatedBean")).isEqualTo(new String[] {"testBean"});
|
||||
}
|
||||
|
||||
@Test
|
||||
void resourceInjectionWithSometimesNullBean() {
|
||||
void resourceInjectionWithSometimesNullBeanEarly() {
|
||||
RootBeanDefinition bd = new RootBeanDefinition(OptionalResourceInjectionBean.class);
|
||||
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
|
||||
bf.registerBeanDefinition("annotatedBean", bd);
|
||||
|
@ -168,6 +174,55 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
|||
assertThat(bean.getTestBean2()).isNull();
|
||||
assertThat(bean.getTestBean3()).isNull();
|
||||
|
||||
SometimesNullFactoryMethods.active = false;
|
||||
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isNull();
|
||||
assertThat(bean.getTestBean2()).isNull();
|
||||
assertThat(bean.getTestBean3()).isNull();
|
||||
|
||||
SometimesNullFactoryMethods.active = true;
|
||||
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isNotNull();
|
||||
assertThat(bean.getTestBean2()).isNotNull();
|
||||
assertThat(bean.getTestBean3()).isNotNull();
|
||||
|
||||
SometimesNullFactoryMethods.active = true;
|
||||
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isNotNull();
|
||||
assertThat(bean.getTestBean2()).isNotNull();
|
||||
assertThat(bean.getTestBean3()).isNotNull();
|
||||
|
||||
SometimesNullFactoryMethods.active = false;
|
||||
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isNull();
|
||||
assertThat(bean.getTestBean2()).isNull();
|
||||
assertThat(bean.getTestBean3()).isNull();
|
||||
|
||||
SometimesNullFactoryMethods.active = false;
|
||||
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isNull();
|
||||
assertThat(bean.getTestBean2()).isNull();
|
||||
assertThat(bean.getTestBean3()).isNull();
|
||||
|
||||
assertThat(bf.getDependenciesForBean("annotatedBean")).isEqualTo(new String[] {"testBean"});
|
||||
}
|
||||
|
||||
@Test
|
||||
void resourceInjectionWithSometimesNullBeanLate() {
|
||||
RootBeanDefinition bd = new RootBeanDefinition(OptionalResourceInjectionBean.class);
|
||||
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
|
||||
bf.registerBeanDefinition("annotatedBean", bd);
|
||||
RootBeanDefinition tb = new RootBeanDefinition(SometimesNullFactoryMethods.class);
|
||||
tb.setFactoryMethodName("createTestBean");
|
||||
tb.setScope(BeanDefinition.SCOPE_PROTOTYPE);
|
||||
bf.registerBeanDefinition("testBean", tb);
|
||||
|
||||
SometimesNullFactoryMethods.active = true;
|
||||
OptionalResourceInjectionBean bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isNotNull();
|
||||
assertThat(bean.getTestBean2()).isNotNull();
|
||||
assertThat(bean.getTestBean3()).isNotNull();
|
||||
|
||||
SometimesNullFactoryMethods.active = true;
|
||||
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isNotNull();
|
||||
|
@ -192,17 +247,13 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
|||
assertThat(bean.getTestBean2()).isNotNull();
|
||||
assertThat(bean.getTestBean3()).isNotNull();
|
||||
|
||||
SometimesNullFactoryMethods.active = true;
|
||||
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isNotNull();
|
||||
assertThat(bean.getTestBean2()).isNotNull();
|
||||
assertThat(bean.getTestBean3()).isNotNull();
|
||||
|
||||
SometimesNullFactoryMethods.active = false;
|
||||
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isNull();
|
||||
assertThat(bean.getTestBean2()).isNull();
|
||||
assertThat(bean.getTestBean3()).isNull();
|
||||
|
||||
assertThat(bf.getDependenciesForBean("annotatedBean")).isEqualTo(new String[] {"testBean"});
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -231,10 +282,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
|||
assertThat(bean.getNestedTestBean()).isSameAs(ntb);
|
||||
assertThat(bean.getBeanFactory()).isSameAs(bf);
|
||||
|
||||
String[] depBeans = bf.getDependenciesForBean("annotatedBean");
|
||||
assertThat(depBeans).hasSize(2);
|
||||
assertThat(depBeans[0]).isEqualTo("testBean");
|
||||
assertThat(depBeans[1]).isEqualTo("nestedTestBean");
|
||||
assertThat(bf.getDependenciesForBean("annotatedBean")).isEqualTo(new String[] {"testBean", "nestedTestBean"});
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -696,6 +744,9 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
|||
assertThat(bean.getTestBean4()).isSameAs(tb);
|
||||
assertThat(bean.getNestedTestBean()).isSameAs(ntb);
|
||||
assertThat(bean.getBeanFactory()).isSameAs(bf);
|
||||
|
||||
assertThat(bf.getDependenciesForBean("annotatedBean")).isEqualTo(
|
||||
new String[] {"testBean", "nestedTestBean", ObjectUtils.identityToString(bf)});
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -858,6 +909,80 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
|||
.satisfies(methodParameterDeclaredOn(ConstructorWithoutFallbackBean.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructorResourceInjectionWithSometimesNullBeanEarly() {
|
||||
RootBeanDefinition bd = new RootBeanDefinition(ConstructorWithNullableArgument.class);
|
||||
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
|
||||
bf.registerBeanDefinition("annotatedBean", bd);
|
||||
RootBeanDefinition tb = new RootBeanDefinition(SometimesNullFactoryMethods.class);
|
||||
tb.setFactoryMethodName("createTestBean");
|
||||
tb.setScope(BeanDefinition.SCOPE_PROTOTYPE);
|
||||
bf.registerBeanDefinition("testBean", tb);
|
||||
|
||||
SometimesNullFactoryMethods.active = false;
|
||||
ConstructorWithNullableArgument bean = (ConstructorWithNullableArgument) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean3()).isNull();
|
||||
|
||||
SometimesNullFactoryMethods.active = false;
|
||||
bean = (ConstructorWithNullableArgument) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean3()).isNull();
|
||||
|
||||
SometimesNullFactoryMethods.active = true;
|
||||
bean = (ConstructorWithNullableArgument) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean3()).isNotNull();
|
||||
|
||||
SometimesNullFactoryMethods.active = true;
|
||||
bean = (ConstructorWithNullableArgument) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean3()).isNotNull();
|
||||
|
||||
SometimesNullFactoryMethods.active = false;
|
||||
bean = (ConstructorWithNullableArgument) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean3()).isNull();
|
||||
|
||||
SometimesNullFactoryMethods.active = false;
|
||||
bean = (ConstructorWithNullableArgument) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean3()).isNull();
|
||||
|
||||
assertThat(bf.getDependenciesForBean("annotatedBean")).isEqualTo(new String[] {"testBean"});
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructorResourceInjectionWithSometimesNullBeanLate() {
|
||||
RootBeanDefinition bd = new RootBeanDefinition(ConstructorWithNullableArgument.class);
|
||||
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
|
||||
bf.registerBeanDefinition("annotatedBean", bd);
|
||||
RootBeanDefinition tb = new RootBeanDefinition(SometimesNullFactoryMethods.class);
|
||||
tb.setFactoryMethodName("createTestBean");
|
||||
tb.setScope(BeanDefinition.SCOPE_PROTOTYPE);
|
||||
bf.registerBeanDefinition("testBean", tb);
|
||||
|
||||
SometimesNullFactoryMethods.active = true;
|
||||
ConstructorWithNullableArgument bean = (ConstructorWithNullableArgument) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean3()).isNotNull();
|
||||
|
||||
SometimesNullFactoryMethods.active = true;
|
||||
bean = (ConstructorWithNullableArgument) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean3()).isNotNull();
|
||||
|
||||
SometimesNullFactoryMethods.active = false;
|
||||
bean = (ConstructorWithNullableArgument) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean3()).isNull();
|
||||
|
||||
SometimesNullFactoryMethods.active = false;
|
||||
bean = (ConstructorWithNullableArgument) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean3()).isNull();
|
||||
|
||||
SometimesNullFactoryMethods.active = true;
|
||||
bean = (ConstructorWithNullableArgument) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean3()).isNotNull();
|
||||
|
||||
SometimesNullFactoryMethods.active = false;
|
||||
bean = (ConstructorWithNullableArgument) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean3()).isNull();
|
||||
|
||||
assertThat(bf.getDependenciesForBean("annotatedBean")).isEqualTo(new String[] {"testBean"});
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructorResourceInjectionWithCollectionAndNullFromFactoryBean() {
|
||||
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(
|
||||
|
@ -2788,6 +2913,21 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
|||
}
|
||||
|
||||
|
||||
public static class ConstructorWithNullableArgument {
|
||||
|
||||
protected ITestBean testBean3;
|
||||
|
||||
@Autowired(required = false)
|
||||
public ConstructorWithNullableArgument(@Nullable ITestBean testBean3) {
|
||||
this.testBean3 = testBean3;
|
||||
}
|
||||
|
||||
public ITestBean getTestBean3() {
|
||||
return this.testBean3;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class ConstructorsCollectionResourceInjectionBean {
|
||||
|
||||
protected ITestBean testBean3;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2023 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.
|
||||
|
@ -123,8 +123,8 @@ public class MethodInvoker {
|
|||
|
||||
/**
|
||||
* Set a fully qualified static method name to invoke,
|
||||
* e.g. "example.MyExampleClass.myExampleMethod".
|
||||
* Convenient alternative to specifying targetClass and targetMethod.
|
||||
* e.g. "example.MyExampleClass.myExampleMethod". This is a
|
||||
* convenient alternative to specifying targetClass and targetMethod.
|
||||
* @see #setTargetClass
|
||||
* @see #setTargetMethod
|
||||
*/
|
||||
|
@ -157,14 +157,16 @@ public class MethodInvoker {
|
|||
public void prepare() throws ClassNotFoundException, NoSuchMethodException {
|
||||
if (this.staticMethod != null) {
|
||||
int lastDotIndex = this.staticMethod.lastIndexOf('.');
|
||||
if (lastDotIndex == -1 || lastDotIndex == this.staticMethod.length()) {
|
||||
if (lastDotIndex == -1 || lastDotIndex == this.staticMethod.length() - 1) {
|
||||
throw new IllegalArgumentException(
|
||||
"staticMethod must be a fully qualified class plus method name: " +
|
||||
"e.g. 'example.MyExampleClass.myExampleMethod'");
|
||||
}
|
||||
String className = this.staticMethod.substring(0, lastDotIndex);
|
||||
String methodName = this.staticMethod.substring(lastDotIndex + 1);
|
||||
this.targetClass = resolveClassName(className);
|
||||
if (this.targetClass == null || !this.targetClass.getName().equals(className)) {
|
||||
this.targetClass = resolveClassName(className);
|
||||
}
|
||||
this.targetMethod = methodName;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2023 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.
|
||||
|
@ -33,57 +33,56 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
*/
|
||||
class ByteBufferConverterTests {
|
||||
|
||||
private GenericConversionService conversionService;
|
||||
private final GenericConversionService conversionService = new DefaultConversionService();
|
||||
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
this.conversionService = new DefaultConversionService();
|
||||
this.conversionService.addConverter(new ByteArrayToOtherTypeConverter());
|
||||
this.conversionService.addConverter(new OtherTypeToByteArrayConverter());
|
||||
conversionService.addConverter(new ByteArrayToOtherTypeConverter());
|
||||
conversionService.addConverter(new OtherTypeToByteArrayConverter());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void byteArrayToByteBuffer() throws Exception {
|
||||
void byteArrayToByteBuffer() {
|
||||
byte[] bytes = new byte[] { 1, 2, 3 };
|
||||
ByteBuffer convert = this.conversionService.convert(bytes, ByteBuffer.class);
|
||||
ByteBuffer convert = conversionService.convert(bytes, ByteBuffer.class);
|
||||
assertThat(convert.array()).isNotSameAs(bytes);
|
||||
assertThat(convert.array()).isEqualTo(bytes);
|
||||
}
|
||||
|
||||
@Test
|
||||
void byteBufferToByteArray() throws Exception {
|
||||
void byteBufferToByteArray() {
|
||||
byte[] bytes = new byte[] { 1, 2, 3 };
|
||||
ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
|
||||
byte[] convert = this.conversionService.convert(byteBuffer, byte[].class);
|
||||
byte[] convert = conversionService.convert(byteBuffer, byte[].class);
|
||||
assertThat(convert).isNotSameAs(bytes);
|
||||
assertThat(convert).isEqualTo(bytes);
|
||||
}
|
||||
|
||||
@Test
|
||||
void byteBufferToOtherType() throws Exception {
|
||||
void byteBufferToOtherType() {
|
||||
byte[] bytes = new byte[] { 1, 2, 3 };
|
||||
ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
|
||||
OtherType convert = this.conversionService.convert(byteBuffer, OtherType.class);
|
||||
OtherType convert = conversionService.convert(byteBuffer, OtherType.class);
|
||||
assertThat(convert.bytes).isNotSameAs(bytes);
|
||||
assertThat(convert.bytes).isEqualTo(bytes);
|
||||
}
|
||||
|
||||
@Test
|
||||
void otherTypeToByteBuffer() throws Exception {
|
||||
void otherTypeToByteBuffer() {
|
||||
byte[] bytes = new byte[] { 1, 2, 3 };
|
||||
OtherType otherType = new OtherType(bytes);
|
||||
ByteBuffer convert = this.conversionService.convert(otherType, ByteBuffer.class);
|
||||
ByteBuffer convert = conversionService.convert(otherType, ByteBuffer.class);
|
||||
assertThat(convert.array()).isNotSameAs(bytes);
|
||||
assertThat(convert.array()).isEqualTo(bytes);
|
||||
}
|
||||
|
||||
@Test
|
||||
void byteBufferToByteBuffer() throws Exception {
|
||||
void byteBufferToByteBuffer() {
|
||||
byte[] bytes = new byte[] { 1, 2, 3 };
|
||||
ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
|
||||
ByteBuffer convert = this.conversionService.convert(byteBuffer, ByteBuffer.class);
|
||||
ByteBuffer convert = conversionService.convert(byteBuffer, ByteBuffer.class);
|
||||
assertThat(convert).isNotSameAs(byteBuffer.rewind());
|
||||
assertThat(convert).isEqualTo(byteBuffer.rewind());
|
||||
assertThat(convert).isEqualTo(ByteBuffer.wrap(bytes));
|
||||
|
|
|
@ -49,11 +49,11 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
|||
*/
|
||||
class CollectionToCollectionConverterTests {
|
||||
|
||||
private GenericConversionService conversionService = new GenericConversionService();
|
||||
private final GenericConversionService conversionService = new GenericConversionService();
|
||||
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
void setup() {
|
||||
conversionService.addConverter(new CollectionToCollectionConverter(conversionService));
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
|||
|
||||
/**
|
||||
* @author Keith Donald
|
||||
* @author Phil Webb
|
||||
* @author Phillip Webb
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
class MapToMapConverterTests {
|
||||
|
@ -47,7 +47,7 @@ class MapToMapConverterTests {
|
|||
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
void setup() {
|
||||
conversionService.addConverter(new MapToMapConverter(conversionService));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2023 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.
|
||||
|
@ -18,6 +18,7 @@ package org.springframework.core.convert.support;
|
|||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.core.convert.ConverterNotFoundException;
|
||||
|
@ -29,15 +30,19 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
|||
* Unit tests for {@link ObjectToObjectConverter}.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @author Phil Webb
|
||||
* @author Phillip Webb
|
||||
* @since 5.3.21
|
||||
* @see org.springframework.core.convert.converter.DefaultConversionServiceTests#convertObjectToObjectUsingValueOfMethod()
|
||||
*/
|
||||
class ObjectToObjectConverterTests {
|
||||
|
||||
private final GenericConversionService conversionService = new GenericConversionService() {{
|
||||
addConverter(new ObjectToObjectConverter());
|
||||
}};
|
||||
private final GenericConversionService conversionService = new GenericConversionService();
|
||||
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
conversionService.addConverter(new ObjectToObjectConverter());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
@ -47,7 +52,7 @@ class ObjectToObjectConverterTests {
|
|||
@Test
|
||||
void nonStaticToTargetTypeSimpleNameMethodWithMatchingReturnType() {
|
||||
assertThat(conversionService.canConvert(Source.class, Data.class))
|
||||
.as("can convert Source to Data").isTrue();
|
||||
.as("can convert Source to Data").isTrue();
|
||||
Data data = conversionService.convert(new Source("test"), Data.class);
|
||||
assertThat(data).asString().isEqualTo("test");
|
||||
}
|
||||
|
@ -55,21 +60,21 @@ class ObjectToObjectConverterTests {
|
|||
@Test
|
||||
void nonStaticToTargetTypeSimpleNameMethodWithDifferentReturnType() {
|
||||
assertThat(conversionService.canConvert(Text.class, Data.class))
|
||||
.as("can convert Text to Data").isFalse();
|
||||
.as("can convert Text to Data").isFalse();
|
||||
assertThat(conversionService.canConvert(Text.class, Optional.class))
|
||||
.as("can convert Text to Optional").isFalse();
|
||||
.as("can convert Text to Optional").isFalse();
|
||||
assertThatExceptionOfType(ConverterNotFoundException.class)
|
||||
.as("convert Text to Data")
|
||||
.isThrownBy(() -> conversionService.convert(new Text("test"), Data.class));
|
||||
.as("convert Text to Data")
|
||||
.isThrownBy(() -> conversionService.convert(new Text("test"), Data.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void staticValueOfFactoryMethodWithDifferentReturnType() {
|
||||
assertThat(conversionService.canConvert(String.class, Data.class))
|
||||
.as("can convert String to Data").isFalse();
|
||||
.as("can convert String to Data").isFalse();
|
||||
assertThatExceptionOfType(ConverterNotFoundException.class)
|
||||
.as("convert String to Data")
|
||||
.isThrownBy(() -> conversionService.convert("test", Data.class));
|
||||
.as("convert String to Data")
|
||||
.isThrownBy(() -> conversionService.convert("test", Data.class));
|
||||
}
|
||||
|
||||
|
||||
|
@ -84,9 +89,9 @@ class ObjectToObjectConverterTests {
|
|||
public Data toData() {
|
||||
return new Data(this.value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static class Text {
|
||||
|
||||
private final String value;
|
||||
|
@ -98,9 +103,9 @@ class ObjectToObjectConverterTests {
|
|||
public Optional<Data> toData() {
|
||||
return Optional.of(new Data(this.value));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static class Data {
|
||||
|
||||
private final String value;
|
||||
|
@ -115,9 +120,8 @@ class ObjectToObjectConverterTests {
|
|||
}
|
||||
|
||||
public static Optional<Data> valueOf(String string) {
|
||||
return (string != null) ? Optional.of(new Data(string)) : Optional.empty();
|
||||
return (string != null ? Optional.of(new Data(string)) : Optional.empty());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue