diff options
author | Emmanuel Bourg <ebourg@apache.org> | 2016-08-03 19:55:01 +0200 |
---|---|---|
committer | Emmanuel Bourg <ebourg@apache.org> | 2016-08-03 19:55:01 +0200 |
commit | 75a721d1019da2a2fa86e24ff439df4a224e5b19 (patch) | |
tree | 2c44c00ce2c8641cccad177177e5682e187a17ea /spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java | |
parent | 9eaca6a06af3cbceb3754de19d477be770614265 (diff) |
Imported Upstream version 4.3.2
Diffstat (limited to 'spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java')
-rw-r--r-- | spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java | 139 |
1 files changed, 87 insertions, 52 deletions
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java index 50c56791..7c871d46 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2016 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. @@ -40,12 +40,14 @@ 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.InjectionPoint; import org.springframework.beans.factory.UnsatisfiedDependencyException; import org.springframework.beans.factory.config.ConstructorArgumentValues; import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder; import org.springframework.beans.factory.config.DependencyDescriptor; import org.springframework.core.GenericTypeResolver; import org.springframework.core.MethodParameter; +import org.springframework.core.NamedThreadLocal; import org.springframework.core.ParameterNameDiscoverer; import org.springframework.util.ClassUtils; import org.springframework.util.MethodInvoker; @@ -68,6 +70,9 @@ import org.springframework.util.StringUtils; */ class ConstructorResolver { + private static final NamedThreadLocal<InjectionPoint> currentInjectionPoint = + new NamedThreadLocal<InjectionPoint>("Current injection point"); + private final AbstractAutowireCapableBeanFactory beanFactory; @@ -151,7 +156,7 @@ class ConstructorResolver { catch (Throwable ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Resolution of declared constructors on bean Class [" + beanClass.getName() + - "] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex); + "] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex); } } AutowireUtils.sortConstructors(candidates); @@ -159,8 +164,7 @@ class ConstructorResolver { Set<Constructor<?>> ambiguousConstructors = null; LinkedList<UnsatisfiedDependencyException> causes = null; - for (int i = 0; i < candidates.length; i++) { - Constructor<?> candidate = candidates[i]; + for (Constructor<?> candidate : candidates) { Class<?>[] paramTypes = candidate.getParameterTypes(); if (constructorToUse != null && argsToUse.length > paramTypes.length) { @@ -182,8 +186,8 @@ class ConstructorResolver { paramNames = pnd.getParameterNames(candidate); } } - argsHolder = createArgumentArray( - beanName, mbd, resolvedValues, bw, paramTypes, paramNames, candidate, autowiring); + argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames, + getUserDeclaredConstructor(candidate), autowiring); } catch (UnsatisfiedDependencyException ex) { if (this.beanFactory.logger.isTraceEnabled()) { @@ -268,7 +272,7 @@ class ConstructorResolver { mbd, beanName, this.beanFactory, constructorToUse, argsToUse); } - bw.setWrappedInstance(beanInstance); + bw.setBeanInstance(beanInstance); return bw; } catch (Throwable ex) { @@ -444,10 +448,9 @@ class ConstructorResolver { minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues); } - List<Exception> causes = null; + LinkedList<UnsatisfiedDependencyException> causes = null; - for (int i = 0; i < candidates.length; i++) { - Method candidate = candidates[i]; + for (Method candidate : candidates) { Class<?>[] paramTypes = candidate.getParameterTypes(); if (paramTypes.length >= minNrOfArgs) { @@ -469,22 +472,12 @@ class ConstructorResolver { this.beanFactory.logger.trace("Ignoring factory method [" + candidate + "] of bean '" + beanName + "': " + ex); } - if (i == candidates.length - 1 && argsHolderToUse == null) { - if (causes != null) { - for (Exception cause : causes) { - this.beanFactory.onSuppressedException(cause); - } - } - throw ex; - } - else { - // Swallow and try next overloaded factory method. - if (causes == null) { - causes = new LinkedList<Exception>(); - } - causes.add(ex); - continue; + // Swallow and try next overloaded factory method. + if (causes == null) { + causes = new LinkedList<UnsatisfiedDependencyException>(); } + causes.add(ex); + continue; } } @@ -525,6 +518,13 @@ class ConstructorResolver { } if (factoryMethodToUse == null) { + if (causes != null) { + UnsatisfiedDependencyException ex = causes.removeLast(); + for (Exception cause : causes) { + this.beanFactory.onSuppressedException(cause); + } + throw ex; + } List<String> argTypes = new ArrayList<String>(minNrOfArgs); if (explicitArgs != null) { for (Object arg : explicitArgs) { @@ -592,7 +592,7 @@ class ConstructorResolver { if (beanInstance == null) { return null; } - bw.setWrappedInstance(beanInstance); + bw.setBeanInstance(beanInstance); return bw; } catch (Throwable ex) { @@ -609,8 +609,8 @@ class ConstructorResolver { private int resolveConstructorArguments(String beanName, RootBeanDefinition mbd, BeanWrapper bw, ConstructorArgumentValues cargs, ConstructorArgumentValues resolvedValues) { - TypeConverter converter = (this.beanFactory.getCustomTypeConverter() != null ? - this.beanFactory.getCustomTypeConverter() : bw); + TypeConverter customConverter = this.beanFactory.getCustomTypeConverter(); + TypeConverter converter = (customConverter != null ? customConverter : bw); BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this.beanFactory, beanName, mbd, converter); @@ -665,9 +665,8 @@ class ConstructorResolver { BeanWrapper bw, Class<?>[] paramTypes, String[] paramNames, Object methodOrCtor, boolean autowiring) throws UnsatisfiedDependencyException { - String methodType = (methodOrCtor instanceof Constructor ? "constructor" : "factory method"); - TypeConverter converter = (this.beanFactory.getCustomTypeConverter() != null ? - this.beanFactory.getCustomTypeConverter() : bw); + TypeConverter customConverter = this.beanFactory.getCustomTypeConverter(); + TypeConverter converter = (customConverter != null ? customConverter : bw); ArgumentsHolder args = new ArgumentsHolder(paramTypes.length); Set<ConstructorArgumentValues.ValueHolder> usedValueHolders = @@ -676,14 +675,14 @@ class ConstructorResolver { for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) { Class<?> paramType = paramTypes[paramIndex]; - String paramName = (paramNames != null ? paramNames[paramIndex] : null); + String paramName = (paramNames != null ? paramNames[paramIndex] : ""); // Try to find matching constructor argument value, either indexed or generic. ConstructorArgumentValues.ValueHolder valueHolder = resolvedValues.getArgumentValue(paramIndex, paramType, paramName, usedValueHolders); // If we couldn't find a direct match and are not supposed to autowire, // let's try the next generic, untyped argument value as fallback: // it could match after type conversion (for example, String -> int). - if (valueHolder == null && !autowiring) { + if (valueHolder == null && (!autowiring || paramTypes.length == resolvedValues.getArgumentCount())) { valueHolder = resolvedValues.getGenericArgumentValue(null, null, usedValueHolders); } if (valueHolder != null) { @@ -700,9 +699,9 @@ class ConstructorResolver { ConstructorArgumentValues.ValueHolder sourceHolder = (ConstructorArgumentValues.ValueHolder) valueHolder.getSource(); Object sourceValue = sourceHolder.getValue(); + MethodParameter methodParam = MethodParameter.forMethodOrConstructor(methodOrCtor, paramIndex); try { - convertedValue = converter.convertIfNecessary(originalValue, paramType, - MethodParameter.forMethodOrConstructor(methodOrCtor, paramIndex)); + convertedValue = converter.convertIfNecessary(originalValue, paramType, methodParam); // TODO re-enable once race condition has been found (SPR-7423) /* if (originalValue == sourceValue || sourceValue instanceof TypedStringValue) { @@ -718,8 +717,8 @@ class ConstructorResolver { } catch (TypeMismatchException ex) { throw new UnsatisfiedDependencyException( - mbd.getResourceDescription(), beanName, paramIndex, paramType, - "Could not convert " + methodType + " argument value of type [" + + mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam), + "Could not convert argument value of type [" + ObjectUtils.nullSafeClassName(valueHolder.getValue()) + "] to required type [" + paramType.getName() + "]: " + ex.getMessage()); } @@ -728,17 +727,18 @@ class ConstructorResolver { args.rawArguments[paramIndex] = originalValue; } else { + MethodParameter methodParam = MethodParameter.forMethodOrConstructor(methodOrCtor, paramIndex); // No explicit match found: we're either supposed to autowire or // have to fail creating an argument array for the given constructor. if (!autowiring) { throw new UnsatisfiedDependencyException( - mbd.getResourceDescription(), beanName, paramIndex, paramType, - "Ambiguous " + methodType + " argument types - " + - "did you specify the correct bean references as " + methodType + " arguments?"); + mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam), + "Ambiguous argument values for parameter of type [" + paramType.getName() + + "] - did you specify the correct bean references as arguments?"); } try { - MethodParameter param = MethodParameter.forMethodOrConstructor(methodOrCtor, paramIndex); - Object autowiredArgument = resolveAutowiredArgument(param, beanName, autowiredBeanNames, converter); + Object autowiredArgument = + resolveAutowiredArgument(methodParam, beanName, autowiredBeanNames, converter); args.rawArguments[paramIndex] = autowiredArgument; args.arguments[paramIndex] = autowiredArgument; args.preparedArguments[paramIndex] = new AutowiredArgumentMarker(); @@ -746,7 +746,7 @@ class ConstructorResolver { } catch (BeansException ex) { throw new UnsatisfiedDependencyException( - mbd.getResourceDescription(), beanName, paramIndex, paramType, ex); + mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam), ex); } } } @@ -755,7 +755,8 @@ class ConstructorResolver { this.beanFactory.registerDependentBean(autowiredBeanName, beanName); if (this.beanFactory.logger.isDebugEnabled()) { this.beanFactory.logger.debug("Autowiring by type from bean name '" + beanName + - "' via " + methodType + " to bean named '" + autowiredBeanName + "'"); + "' via " + (methodOrCtor instanceof Constructor ? "constructor" : "factory method") + + " to bean named '" + autowiredBeanName + "'"); } } @@ -768,12 +769,13 @@ class ConstructorResolver { private Object[] resolvePreparedArguments( String beanName, RootBeanDefinition mbd, BeanWrapper bw, Member methodOrCtor, Object[] argsToResolve) { - Class<?>[] paramTypes = (methodOrCtor instanceof Method ? - ((Method) methodOrCtor).getParameterTypes() : ((Constructor<?>) methodOrCtor).getParameterTypes()); - TypeConverter converter = (this.beanFactory.getCustomTypeConverter() != null ? - this.beanFactory.getCustomTypeConverter() : bw); + TypeConverter customConverter = this.beanFactory.getCustomTypeConverter(); + TypeConverter converter = (customConverter != null ? customConverter : bw); BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this.beanFactory, beanName, mbd, converter); + Class<?>[] paramTypes = (methodOrCtor instanceof Method ? + ((Method) methodOrCtor).getParameterTypes() : ((Constructor<?>) methodOrCtor).getParameterTypes()); + Object[] resolvedArgs = new Object[argsToResolve.length]; for (int argIndex = 0; argIndex < argsToResolve.length; argIndex++) { Object argValue = argsToResolve[argIndex]; @@ -793,28 +795,61 @@ class ConstructorResolver { resolvedArgs[argIndex] = converter.convertIfNecessary(argValue, paramType, methodParam); } catch (TypeMismatchException ex) { - String methodType = (methodOrCtor instanceof Constructor ? "constructor" : "factory method"); throw new UnsatisfiedDependencyException( - mbd.getResourceDescription(), beanName, argIndex, paramType, - "Could not convert " + methodType + " argument value of type [" + - ObjectUtils.nullSafeClassName(argValue) + + mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam), + "Could not convert argument value of type [" + ObjectUtils.nullSafeClassName(argValue) + "] to required type [" + paramType.getName() + "]: " + ex.getMessage()); } } return resolvedArgs; } + protected Constructor<?> getUserDeclaredConstructor(Constructor<?> constructor) { + Class<?> declaringClass = constructor.getDeclaringClass(); + Class<?> userClass = ClassUtils.getUserClass(declaringClass); + if (userClass != declaringClass) { + try { + return userClass.getDeclaredConstructor(constructor.getParameterTypes()); + } + catch (NoSuchMethodException ex) { + // No equivalent constructor on user class (superclass)... + // Let's proceed with the given constructor as we usually would. + } + } + return constructor; + } + /** * Template method for resolving the specified argument which is supposed to be autowired. */ protected Object resolveAutowiredArgument( MethodParameter param, String beanName, Set<String> autowiredBeanNames, TypeConverter typeConverter) { + if (InjectionPoint.class.isAssignableFrom(param.getParameterType())) { + InjectionPoint injectionPoint = currentInjectionPoint.get(); + if (injectionPoint == null) { + throw new IllegalStateException("No current InjectionPoint available for " + param); + } + return injectionPoint; + } return this.beanFactory.resolveDependency( new DependencyDescriptor(param, true), beanName, autowiredBeanNames, typeConverter); } + + static InjectionPoint setCurrentInjectionPoint(InjectionPoint injectionPoint) { + InjectionPoint old = currentInjectionPoint.get(); + if (injectionPoint != null) { + currentInjectionPoint.set(injectionPoint); + } + else { + currentInjectionPoint.remove(); + } + return old; + } + + /** * Private inner class for holding argument combinations. */ |