use of cn.taketoday.beans.TypeConverter in project today-framework by TAKETODAY.
the class ConstructorResolver method resolvePreparedArguments.
/**
* Resolve the prepared arguments stored in the given bean definition.
*/
private Object[] resolvePreparedArguments(String beanName, BeanDefinition merged, Executable executable, Object[] argsToResolve, BeanWrapper bw) {
TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
TypeConverter converter = customConverter != null ? customConverter : bw;
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(beanFactory, beanName, merged, converter);
Class<?>[] paramTypes = executable.getParameterTypes();
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(methodParam, beanName, null, converter, true);
} else if (argValue instanceof BeanMetadataElement) {
argValue = valueResolver.resolveValueIfNecessary("constructor argument", argValue);
} else if (argValue instanceof String) {
argValue = beanFactory.evaluateBeanDefinitionString((String) argValue, merged);
}
Class<?> paramType = paramTypes[argIndex];
try {
resolvedArgs[argIndex] = converter.convertIfNecessary(argValue, paramType, methodParam);
} catch (TypeMismatchException ex) {
throw new UnsatisfiedDependencyException(merged.getResourceDescription(), beanName, new InjectionPoint(methodParam), "Could not convert argument value of type [" + ObjectUtils.nullSafeClassName(argValue) + "] to required type [" + paramType.getName() + "]: " + ex.getMessage());
}
}
return resolvedArgs;
}
use of cn.taketoday.beans.TypeConverter in project today-framework by TAKETODAY.
the class ConstructorResolver method resolveConstructorArguments.
/**
* Resolve the constructor arguments for this bean into the resolvedValues object.
* This may involve looking up other beans.
* <p>This method is also used for handling invocations of static factory methods.
*/
private int resolveConstructorArguments(String beanName, BeanDefinition merged, BeanWrapper bw, ConstructorArgumentValues cargs, ConstructorArgumentValues resolvedValues) {
TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
TypeConverter converter = customConverter != null ? customConverter : bw;
var valueResolver = new BeanDefinitionValueResolver(this.beanFactory, beanName, merged, converter);
int minNrOfArgs = cargs.getArgumentCount();
for (Map.Entry<Integer, ValueHolder> entry : cargs.getIndexedArgumentValues().entrySet()) {
int index = entry.getKey();
if (index < 0) {
throw new BeanCreationException(merged.getResourceDescription(), beanName, "Invalid constructor argument index: " + index);
}
if (index + 1 > minNrOfArgs) {
minNrOfArgs = index + 1;
}
ValueHolder valueHolder = entry.getValue();
if (valueHolder.isConverted()) {
resolvedValues.addIndexedArgumentValue(index, valueHolder);
} else {
Object resolvedValue = valueResolver.resolveValueIfNecessary("constructor argument", valueHolder.getValue());
ValueHolder resolvedValueHolder = new ValueHolder(resolvedValue, valueHolder.getType(), valueHolder.getName());
resolvedValueHolder.setSource(valueHolder);
resolvedValues.addIndexedArgumentValue(index, resolvedValueHolder);
}
}
for (ValueHolder valueHolder : cargs.getGenericArgumentValues()) {
if (valueHolder.isConverted()) {
resolvedValues.addGenericArgumentValue(valueHolder);
} else {
Object resolvedValue = valueResolver.resolveValueIfNecessary("constructor argument", valueHolder.getValue());
ValueHolder resolvedValueHolder = new ValueHolder(resolvedValue, valueHolder.getType(), valueHolder.getName());
resolvedValueHolder.setSource(valueHolder);
resolvedValues.addGenericArgumentValue(resolvedValueHolder);
}
}
return minNrOfArgs;
}
use of cn.taketoday.beans.TypeConverter in project today-framework by TAKETODAY.
the class ConstructorResolver method createArgumentArray.
/**
* Create an array of arguments to invoke a constructor or factory method,
* given the resolved constructor argument values.
*/
private ArgumentsHolder createArgumentArray(String beanName, RootBeanDefinition merged, @Nullable ConstructorArgumentValues resolvedValues, Class<?>[] paramTypes, @Nullable String[] paramNames, Executable executable, BeanWrapper wrapper, boolean autowiring, boolean fallback) throws UnsatisfiedDependencyException {
TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
TypeConverter converter = customConverter != null ? customConverter : wrapper;
ArgumentsHolder args = new ArgumentsHolder(paramTypes.length);
HashSet<ValueHolder> usedValueHolders = new HashSet<>(paramTypes.length);
LinkedHashSet<String> autowiredBeanNames = new LinkedHashSet<>(4);
for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {
Class<?> paramType = paramTypes[paramIndex];
String paramName = paramNames != null ? paramNames[paramIndex] : "";
// Try to find matching constructor argument value, either indexed or generic.
ValueHolder valueHolder = null;
if (resolvedValues != null) {
valueHolder = resolvedValues.getArgumentValue(paramIndex, paramType, paramName, usedValueHolders);
// it could match after type conversion (for example, String -> int).
if (valueHolder == null && (!autowiring || paramTypes.length == resolvedValues.getArgumentCount())) {
valueHolder = resolvedValues.getGenericArgumentValue(null, null, usedValueHolders);
}
}
if (valueHolder != null) {
// We found a potential match - let's give it a try.
// Do not consider the same value definition multiple times!
usedValueHolders.add(valueHolder);
Object originalValue = valueHolder.getValue();
Object convertedValue;
if (valueHolder.isConverted()) {
convertedValue = valueHolder.getConvertedValue();
args.preparedArguments[paramIndex] = convertedValue;
} else {
MethodParameter methodParam = MethodParameter.forExecutable(executable, paramIndex);
try {
convertedValue = converter.convertIfNecessary(originalValue, paramType, methodParam);
} catch (TypeMismatchException ex) {
throw new UnsatisfiedDependencyException(merged.getResourceDescription(), beanName, new InjectionPoint(methodParam), "Could not convert argument value of type [" + ObjectUtils.nullSafeClassName(valueHolder.getValue()) + "] to required type [" + paramType.getName() + "]: " + ex.getMessage());
}
Object sourceHolder = valueHolder.getSource();
if (sourceHolder instanceof ValueHolder) {
Object sourceValue = ((ValueHolder) sourceHolder).getValue();
args.resolveNecessary = true;
args.preparedArguments[paramIndex] = sourceValue;
}
}
args.arguments[paramIndex] = convertedValue;
args.rawArguments[paramIndex] = originalValue;
} else {
MethodParameter methodParam = MethodParameter.forExecutable(executable, paramIndex);
// have to fail creating an argument array for the given constructor.
if (!autowiring) {
throw new UnsatisfiedDependencyException(merged.getResourceDescription(), beanName, new InjectionPoint(methodParam), "Ambiguous argument values for parameter of type [" + paramType.getName() + "] - did you specify the correct bean references as arguments?");
}
try {
Object autowiredArgument = resolveAutowiredArgument(methodParam, beanName, autowiredBeanNames, converter, fallback);
args.resolveNecessary = true;
args.arguments[paramIndex] = autowiredArgument;
args.rawArguments[paramIndex] = autowiredArgument;
args.preparedArguments[paramIndex] = autowiredArgumentMarker;
} catch (BeansException ex) {
throw new UnsatisfiedDependencyException(merged.getResourceDescription(), beanName, new InjectionPoint(methodParam), ex);
}
}
}
for (String autowiredBeanName : autowiredBeanNames) {
beanFactory.registerDependentBean(autowiredBeanName, beanName);
if (log.isDebugEnabled()) {
log.debug("Autowiring by type from bean name '{}' via {} to bean named '{}'", beanName, (executable instanceof Constructor ? "constructor" : "factory method"), autowiredBeanName);
}
}
return args;
}
use of cn.taketoday.beans.TypeConverter in project today-framework by TAKETODAY.
the class ArgumentConvertingMethodInvoker method registerCustomEditor.
/**
* Register the given custom property editor for all properties of the given type.
* <p>Typically used in conjunction with the default
* {@link cn.taketoday.beans.SimpleTypeConverter}; will work with any
* TypeConverter that implements the PropertyEditorRegistry interface as well.
*
* @param requiredType type of the property
* @param propertyEditor editor to register
* @see #setTypeConverter
* @see cn.taketoday.beans.PropertyEditorRegistry#registerCustomEditor
*/
public void registerCustomEditor(Class<?> requiredType, PropertyEditor propertyEditor) {
TypeConverter converter = getTypeConverter();
if (!(converter instanceof PropertyEditorRegistry)) {
throw new IllegalStateException("TypeConverter does not implement PropertyEditorRegistry interface: " + converter);
}
((PropertyEditorRegistry) converter).registerCustomEditor(requiredType, propertyEditor);
}
use of cn.taketoday.beans.TypeConverter in project today-framework by TAKETODAY.
the class ArgumentConvertingMethodInvoker method doFindMatchingMethod.
/**
* Actually find a method with matching parameter type, i.e. where each
* argument value is assignable to the corresponding parameter type.
*
* @param arguments the argument values to match against method parameters
* @return a matching method, or {@code null} if none
*/
@Nullable
protected Method doFindMatchingMethod(Object[] arguments) {
TypeConverter converter = getTypeConverter();
if (converter != null) {
String targetMethod = getTargetMethod();
Method matchingMethod = null;
int argCount = arguments.length;
Class<?> targetClass = getTargetClass();
Assert.state(targetClass != null, "No target class set");
Method[] candidates = ReflectionUtils.getAllDeclaredMethods(targetClass);
int minTypeDiffWeight = Integer.MAX_VALUE;
Object[] argumentsToUse = null;
for (Method candidate : candidates) {
if (candidate.getName().equals(targetMethod)) {
// Check if the inspected method has the correct number of parameters.
int parameterCount = candidate.getParameterCount();
if (parameterCount == argCount) {
Class<?>[] paramTypes = candidate.getParameterTypes();
Object[] convertedArguments = new Object[argCount];
boolean match = true;
for (int j = 0; j < argCount && match; j++) {
// Verify that the supplied argument is assignable to the method parameter.
try {
convertedArguments[j] = converter.convertIfNecessary(arguments[j], paramTypes[j]);
} catch (TypeMismatchException ex) {
// Ignore -> simply doesn't match.
match = false;
}
}
if (match) {
int typeDiffWeight = getTypeDifferenceWeight(paramTypes, convertedArguments);
if (typeDiffWeight < minTypeDiffWeight) {
minTypeDiffWeight = typeDiffWeight;
matchingMethod = candidate;
argumentsToUse = convertedArguments;
}
}
}
}
}
if (matchingMethod != null) {
setArguments(argumentsToUse);
return matchingMethod;
}
}
return null;
}
Aggregations