XML constructor-arg element allows for specifying a constructor argument by name now, with target argument names read from the class file via ASM or from Java 6's @ConstructorProperties annotation (SPR-3313)

This commit is contained in:
Juergen Hoeller
2009-06-03 10:21:57 +00:00
parent 0a0b10b2ff
commit 53333c3ed0
18 changed files with 530 additions and 141 deletions

View File

@@ -139,13 +139,27 @@ public class ConstructorArgumentValues {
* @return the ValueHolder for the argument, or <code>null</code> if none set
*/
public ValueHolder getIndexedArgumentValue(int index, Class requiredType) {
return getIndexedArgumentValue(index, requiredType, null);
}
/**
* Get argument value for the given index in the constructor argument list.
* @param index the index in the constructor argument list
* @param requiredType the type to match (can be <code>null</code> to match
* untyped values only)
* @param requiredName the type to match (can be <code>null</code> to match
* unnamed values only)
* @return the ValueHolder for the argument, or <code>null</code> if none set
*/
public ValueHolder getIndexedArgumentValue(int index, Class requiredType, String requiredName) {
Assert.isTrue(index >= 0, "Index must not be negative");
ValueHolder valueHolder = this.indexedArgumentValues.get(index);
if (valueHolder != null) {
if (valueHolder.getType() == null ||
(requiredType != null && requiredType.getName().equals(valueHolder.getType()))) {
return valueHolder;
}
if (valueHolder != null &&
(valueHolder.getType() == null ||
(requiredType != null && requiredType.getName().equals(valueHolder.getType()))) &&
(valueHolder.getName() == null ||
(requiredName != null && requiredName.equals(valueHolder.getName())))) {
return valueHolder;
}
return null;
}
@@ -163,7 +177,7 @@ public class ConstructorArgumentValues {
/**
* Add generic argument value to be matched by type.
* <p>Note: A single generic argument value will just be used once,
* rather than matched multiple times (as of Spring 1.1).
* rather than matched multiple times.
* @param value the argument value
*/
public void addGenericArgumentValue(Object value) {
@@ -173,7 +187,7 @@ public class ConstructorArgumentValues {
/**
* Add generic argument value to be matched by type.
* <p>Note: A single generic argument value will just be used once,
* rather than matched multiple times (as of Spring 1.1).
* rather than matched multiple times.
* @param value the argument value
* @param type the type of the constructor argument
*/
@@ -184,7 +198,7 @@ public class ConstructorArgumentValues {
/**
* Add generic argument value to be matched by type.
* <p>Note: A single generic argument value will just be used once,
* rather than matched multiple times (as of Spring 1.1).
* rather than matched multiple times.
* @param newValue the argument value in the form of a ValueHolder
* <p>Note: Identical ValueHolder instances will only be registered once,
* to allow for merging and re-merging of argument value definitions. Distinct
@@ -199,12 +213,21 @@ public class ConstructorArgumentValues {
/**
* Look for a generic argument value that matches the given type.
* @param requiredType the type to match (can be <code>null</code> to find
* an arbitrary next generic argument value)
* @param requiredType the type to match
* @return the ValueHolder for the argument, or <code>null</code> if none set
*/
public ValueHolder getGenericArgumentValue(Class requiredType) {
return getGenericArgumentValue(requiredType, null);
return getGenericArgumentValue(requiredType, null, null);
}
/**
* Look for a generic argument value that matches the given type.
* @param requiredType the type to match
* @param requiredName the name to match
* @return the ValueHolder for the argument, or <code>null</code> if none set
*/
public ValueHolder getGenericArgumentValue(Class requiredType, String requiredName) {
return getGenericArgumentValue(requiredType, requiredName, null);
}
/**
@@ -213,16 +236,23 @@ public class ConstructorArgumentValues {
* resolution process.
* @param requiredType the type to match (can be <code>null</code> to find
* an arbitrary next generic argument value)
* @param requiredName the type to match (can be <code>null</code> to match
* unnamed values only)
* @param usedValueHolders a Set of ValueHolder objects that have already been used
* in the current resolution process and should therefore not be returned again
* @return the ValueHolder for the argument, or <code>null</code> if none found
*/
public ValueHolder getGenericArgumentValue(Class requiredType, Set usedValueHolders) {
public ValueHolder getGenericArgumentValue(Class requiredType, String requiredName, Set<ValueHolder> usedValueHolders) {
for (ValueHolder valueHolder : this.genericArgumentValues) {
if (usedValueHolders == null || !usedValueHolders.contains(valueHolder)) {
if (requiredType != null) {
// Check matching type.
if (valueHolder.getType() != null) {
if (valueHolder.getName() != null) {
if (valueHolder.getName().equals(requiredName)) {
return valueHolder;
}
}
else if (valueHolder.getType() != null) {
if (valueHolder.getType().equals(requiredType.getName())) {
return valueHolder;
}
@@ -260,7 +290,19 @@ public class ConstructorArgumentValues {
* @return the ValueHolder for the argument, or <code>null</code> if none set
*/
public ValueHolder getArgumentValue(int index, Class requiredType) {
return getArgumentValue(index, requiredType, null);
return getArgumentValue(index, requiredType, null, null);
}
/**
* Look for an argument value that either corresponds to the given index
* in the constructor argument list or generically matches by type.
* @param index the index in the constructor argument list
* @param requiredType the type to match
* @param requiredName the name to match
* @return the ValueHolder for the argument, or <code>null</code> if none set
*/
public ValueHolder getArgumentValue(int index, Class requiredType, String requiredName) {
return getArgumentValue(index, requiredType, requiredName, null);
}
/**
@@ -275,11 +317,11 @@ public class ConstructorArgumentValues {
* in case of multiple generic argument values of the same type)
* @return the ValueHolder for the argument, or <code>null</code> if none set
*/
public ValueHolder getArgumentValue(int index, Class requiredType, Set usedValueHolders) {
public ValueHolder getArgumentValue(int index, Class requiredType, String requiredName, Set<ValueHolder> usedValueHolders) {
Assert.isTrue(index >= 0, "Index must not be negative");
ValueHolder valueHolder = getIndexedArgumentValue(index, requiredType);
ValueHolder valueHolder = getIndexedArgumentValue(index, requiredType, requiredName);
if (valueHolder == null) {
valueHolder = getGenericArgumentValue(requiredType, usedValueHolders);
valueHolder = getGenericArgumentValue(requiredType, requiredName, usedValueHolders);
}
return valueHolder;
}
@@ -365,6 +407,8 @@ public class ConstructorArgumentValues {
private String type;
private String name;
private Object source;
private boolean converted = false;
@@ -389,10 +433,20 @@ public class ConstructorArgumentValues {
this.type = type;
}
/**
* Create a new ValueHolder for the given value, type and name.
* @param value the argument value
* @param type the type of the constructor argument
* @param name the name of the constructor argument
*/
public ValueHolder(Object value, String type, String name) {
this.value = value;
this.type = type;
this.name = name;
}
/**
* Set the value for the constructor argument.
* Only necessary for manipulating a registered value,
* for example in BeanFactoryPostProcessors.
* @see PropertyPlaceholderConfigurer
*/
public void setValue(Object value) {
@@ -408,9 +462,6 @@ public class ConstructorArgumentValues {
/**
* Set the type of the constructor argument.
* Only necessary for manipulating a registered value,
* for example in BeanFactoryPostProcessors.
* @see PropertyPlaceholderConfigurer
*/
public void setType(String type) {
this.type = type;
@@ -423,6 +474,20 @@ public class ConstructorArgumentValues {
return this.type;
}
/**
* Set the name of the constructor argument.
*/
public void setName(String name) {
this.name = name;
}
/**
* Return the name of the constructor argument.
*/
public String getName() {
return this.name;
}
/**
* Set the configuration source <code>Object</code> for this metadata element.
* <p>The exact type of the object will depend on the configuration mechanism used.
@@ -487,7 +552,7 @@ public class ConstructorArgumentValues {
* ValueHolder instance with the same contents.
*/
public ValueHolder copy() {
ValueHolder copy = new ValueHolder(this.value, this.type);
ValueHolder copy = new ValueHolder(this.value, this.type, this.name);
copy.setSource(this.source);
return copy;
}

View File

@@ -67,6 +67,7 @@ import org.springframework.beans.factory.config.InstantiationAwareBeanPostProces
import org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor;
import org.springframework.beans.factory.config.TypedStringValue;
import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.PriorityOrdered;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
@@ -108,8 +109,12 @@ import org.springframework.util.StringUtils;
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
/** Strategy for creating bean instances */
private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();
/** Resolver strategy for method parameter names */
private ParameterNameDiscoverer parameterNameDiscoverer;
/** Whether to automatically try to resolve circular references between beans */
private boolean allowCircularReferences = true;
@@ -176,6 +181,25 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
return this.instantiationStrategy;
}
/**
* Set the ParameterNameDiscoverer to use for resolving method parameter
* names if needed (e.g. for constructor names).
* <p>Default is none. A typical candidate is
* {@link org.springframework.core.LocalVariableTableParameterNameDiscoverer},
* which implies an ASM dependency and hence isn't set as the default.
*/
public void setParameterNameDiscoverer(ParameterNameDiscoverer parameterNameDiscoverer) {
this.parameterNameDiscoverer = parameterNameDiscoverer;
}
/**
* Return the ParameterNameDiscoverer to use for resolving method parameter
* names if needed.
*/
protected ParameterNameDiscoverer getParameterNameDiscoverer() {
return this.parameterNameDiscoverer;
}
/**
* Set whether to allow circular references between beans - and automatically
* try to resolve them.
@@ -822,9 +846,9 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
}
// Shortcut when re-creating the same bean...
if (mbd.resolvedConstructorOrFactoryMethod != null) {
if (mbd.resolvedConstructorOrFactoryMethod != null && args == null) {
if (mbd.constructorArgumentsResolved) {
return autowireConstructor(beanName, mbd, null, args);
return autowireConstructor(beanName, mbd, null, null);
}
else {
return instantiateBean(beanName, mbd);
@@ -901,9 +925,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
protected BeanWrapper instantiateUsingFactoryMethod(
String beanName, RootBeanDefinition mbd, Object[] explicitArgs) {
ConstructorResolver constructorResolver =
new ConstructorResolver(this, this, getInstantiationStrategy(), getCustomTypeConverter());
return constructorResolver.instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);
return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);
}
/**
@@ -923,9 +945,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
protected BeanWrapper autowireConstructor(
String beanName, RootBeanDefinition mbd, Constructor[] ctors, Object[] explicitArgs) {
ConstructorResolver constructorResolver =
new ConstructorResolver(this, this, getInstantiationStrategy(), getCustomTypeConverter());
return constructorResolver.autowireConstructor(beanName, mbd, ctors, explicitArgs);
return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);
}
/**

View File

@@ -16,6 +16,7 @@
package org.springframework.beans.factory.support;
import java.beans.ConstructorProperties;
import java.lang.reflect.Constructor;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
@@ -38,12 +39,12 @@ import org.springframework.beans.TypeMismatchException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.UnsatisfiedDependencyException;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.config.TypedStringValue;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.util.ClassUtils;
import org.springframework.util.MethodInvoker;
import org.springframework.util.ObjectUtils;
@@ -66,29 +67,20 @@ import org.springframework.util.ReflectionUtils;
*/
class ConstructorResolver {
private final AbstractBeanFactory beanFactory;
private static final String CONSTRUCTOR_PROPERTIES_CLASS_NAME = "java.beans.ConstructorProperties";
private final AutowireCapableBeanFactory autowireFactory;
private static final boolean constructorPropertiesAnnotationAvailable =
ClassUtils.isPresent(CONSTRUCTOR_PROPERTIES_CLASS_NAME, ConstructorResolver.class.getClassLoader());
private final InstantiationStrategy instantiationStrategy;
private final TypeConverter typeConverter;
private final AbstractAutowireCapableBeanFactory beanFactory;
/**
* Create a new ConstructorResolver for the given factory and instantiation strategy.
* @param beanFactory the BeanFactory to work with
* @param autowireFactory the BeanFactory as AutowireCapableBeanFactory
* @param instantiationStrategy the instantiate strategy for creating bean instances
* @param typeConverter the TypeConverter to use (or <code>null</code> for using the default)
*/
public ConstructorResolver(AbstractBeanFactory beanFactory, AutowireCapableBeanFactory autowireFactory,
InstantiationStrategy instantiationStrategy, TypeConverter typeConverter) {
public ConstructorResolver(AbstractAutowireCapableBeanFactory beanFactory) {
this.beanFactory = beanFactory;
this.autowireFactory = autowireFactory;
this.instantiationStrategy = instantiationStrategy;
this.typeConverter = typeConverter;
}
@@ -162,7 +154,7 @@ class ConstructorResolver {
int minTypeDiffWeight = Integer.MAX_VALUE;
for (int i = 0; i < candidates.length; i++) {
Constructor candidate = candidates[i];
Constructor<?> candidate = candidates[i];
Class[] paramTypes = candidate.getParameterTypes();
if (constructorToUse != null && argsToUse.length > paramTypes.length) {
@@ -174,17 +166,26 @@ class ConstructorResolver {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
minNrOfArgs + " constructor arguments specified but no matching constructor found in bean '" +
beanName + "' " +
"(hint: specify index and/or type arguments for simple parameters to avoid type ambiguities)");
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)");
}
ArgumentsHolder args;
List<Exception> causes = null;
if (resolvedValues != null) {
// Try to resolve arguments for current constructor.
try {
String[] paramNames = null;
if (constructorPropertiesAnnotationAvailable) {
paramNames = ConstructorPropertiesChecker.evaluateAnnotation(candidate, paramTypes.length);
}
if (paramNames == null) {
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
if (pnd != null) {
paramNames = pnd.getParameterNames(candidate);
}
}
args = createArgumentArray(
beanName, mbd, resolvedValues, bw, paramTypes, candidate, autowiring);
beanName, mbd, resolvedValues, bw, paramTypes, paramNames, candidate, autowiring);
}
catch (UnsatisfiedDependencyException ex) {
if (this.beanFactory.logger.isTraceEnabled()) {
@@ -238,7 +239,7 @@ class ConstructorResolver {
}
try {
Object beanInstance = this.instantiationStrategy.instantiate(
Object beanInstance = this.beanFactory.getInstantiationStrategy().instantiate(
mbd, beanName, this.beanFactory, constructorToUse, argsToUse);
bw.setWrappedInstance(beanInstance);
return bw;
@@ -385,10 +386,15 @@ class ConstructorResolver {
ArgumentsHolder args;
if (resolvedValues != null) {
// Resolved contructor arguments: type conversion and/or autowiring necessary.
// Resolved constructor arguments: type conversion and/or autowiring necessary.
try {
String[] paramNames = null;
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
if (pnd != null) {
paramNames = pnd.getParameterNames(candidate);
}
args = createArgumentArray(
beanName, mbd, resolvedValues, bw, paramTypes, candidate, autowiring);
beanName, mbd, resolvedValues, bw, paramTypes, paramNames, candidate, autowiring);
}
catch (UnsatisfiedDependencyException ex) {
if (this.beanFactory.logger.isTraceEnabled()) {
@@ -451,7 +457,7 @@ class ConstructorResolver {
}
try {
Object beanInstance = this.instantiationStrategy.instantiate(
Object beanInstance = this.beanFactory.getInstantiationStrategy().instantiate(
mbd, beanName, this.beanFactory, factoryBean, factoryMethodToUse, argsToUse);
if (beanInstance == null) {
return null;
@@ -473,9 +479,10 @@ class ConstructorResolver {
String beanName, RootBeanDefinition mbd, BeanWrapper bw,
ConstructorArgumentValues cargs, ConstructorArgumentValues resolvedValues) {
TypeConverter converterToUse = (this.typeConverter != null ? this.typeConverter : bw);
TypeConverter converter = (this.beanFactory.getCustomTypeConverter() != null ?
this.beanFactory.getCustomTypeConverter() : bw);
BeanDefinitionValueResolver valueResolver =
new BeanDefinitionValueResolver(this.beanFactory, beanName, mbd, converterToUse);
new BeanDefinitionValueResolver(this.beanFactory, beanName, mbd, converter);
int minNrOfArgs = cargs.getArgumentCount();
@@ -496,7 +503,7 @@ class ConstructorResolver {
Object resolvedValue =
valueResolver.resolveValueIfNecessary("constructor argument", valueHolder.getValue());
ConstructorArgumentValues.ValueHolder resolvedValueHolder =
new ConstructorArgumentValues.ValueHolder(resolvedValue, valueHolder.getType());
new ConstructorArgumentValues.ValueHolder(resolvedValue, valueHolder.getType(), valueHolder.getName());
resolvedValueHolder.setSource(valueHolder);
resolvedValues.addIndexedArgumentValue(index, resolvedValueHolder);
}
@@ -510,7 +517,7 @@ class ConstructorResolver {
Object resolvedValue =
valueResolver.resolveValueIfNecessary("constructor argument", valueHolder.getValue());
ConstructorArgumentValues.ValueHolder resolvedValueHolder =
new ConstructorArgumentValues.ValueHolder(resolvedValue, valueHolder.getType());
new ConstructorArgumentValues.ValueHolder(resolvedValue, valueHolder.getType(), valueHolder.getName());
resolvedValueHolder.setSource(valueHolder);
resolvedValues.addGenericArgumentValue(resolvedValueHolder);
}
@@ -525,11 +532,12 @@ class ConstructorResolver {
*/
private ArgumentsHolder createArgumentArray(
String beanName, RootBeanDefinition mbd, ConstructorArgumentValues resolvedValues,
BeanWrapper bw, Class[] paramTypes, Object methodOrCtor, boolean autowiring)
throws UnsatisfiedDependencyException {
BeanWrapper bw, Class[] paramTypes, String[] paramNames, Object methodOrCtor,
boolean autowiring) throws UnsatisfiedDependencyException {
String methodType = (methodOrCtor instanceof Constructor ? "constructor" : "factory method");
TypeConverter converter = (this.typeConverter != null ? this.typeConverter : bw);
TypeConverter converter = (this.beanFactory.getCustomTypeConverter() != null ?
this.beanFactory.getCustomTypeConverter() : bw);
ArgumentsHolder args = new ArgumentsHolder(paramTypes.length);
Set<ConstructorArgumentValues.ValueHolder> usedValueHolders =
@@ -538,15 +546,16 @@ class ConstructorResolver {
boolean resolveNecessary = false;
for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {
Class paramType = paramTypes[paramIndex];
Class<?> paramType = paramTypes[paramIndex];
String paramName = (paramNames != null ? paramNames[paramIndex] : null);
// Try to find matching constructor argument value, either indexed or generic.
ConstructorArgumentValues.ValueHolder valueHolder =
resolvedValues.getArgumentValue(paramIndex, paramType, usedValueHolders);
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) {
valueHolder = resolvedValues.getGenericArgumentValue(null, usedValueHolders);
valueHolder = resolvedValues.getGenericArgumentValue(null, null, usedValueHolders);
}
if (valueHolder != null) {
// We found a potential match - let's give it a try.
@@ -637,7 +646,8 @@ class ConstructorResolver {
Class[] paramTypes = (methodOrCtor instanceof Method ?
((Method) methodOrCtor).getParameterTypes() : ((Constructor) methodOrCtor).getParameterTypes());
Object[] argsToResolve = mbd.preparedConstructorArguments;
TypeConverter converter = (this.typeConverter != null ? this.typeConverter : bw);
TypeConverter converter = (this.beanFactory.getCustomTypeConverter() != null ?
this.beanFactory.getCustomTypeConverter() : bw);
BeanDefinitionValueResolver valueResolver =
new BeanDefinitionValueResolver(this.beanFactory, beanName, mbd, converter);
Object[] resolvedArgs = new Object[argsToResolve.length];
@@ -654,7 +664,7 @@ class ConstructorResolver {
else if (argValue instanceof String) {
argValue = this.beanFactory.evaluateBeanDefinitionString((String) argValue, mbd);
}
Class paramType = paramTypes[argIndex];
Class<?> paramType = paramTypes[argIndex];
try {
resolvedArgs[argIndex] = converter.convertIfNecessary(argValue, paramType, methodParam);
}
@@ -676,7 +686,7 @@ class ConstructorResolver {
protected Object resolveAutowiredArgument(
MethodParameter param, String beanName, Set<String> autowiredBeanNames, TypeConverter typeConverter) {
return this.autowireFactory.resolveDependency(
return this.beanFactory.resolveDependency(
new DependencyDescriptor(param, true), beanName, autowiredBeanNames, typeConverter);
}
@@ -722,4 +732,26 @@ class ConstructorResolver {
private static class AutowiredArgumentMarker {
}
/**
* Inner class to avoid a Java 6 dependency.
*/
private static class ConstructorPropertiesChecker {
public static String[] evaluateAnnotation(Constructor<?> candidate, int paramCount) {
ConstructorProperties cp = candidate.getAnnotation(ConstructorProperties.class);
if (cp != null) {
String[] names = cp.value();
if (names.length != paramCount) {
throw new IllegalStateException("Constructor annotated with @ConstructorProperties but not " +
"corresponding to actual number of parameters (" + paramCount + "): " + candidate);
}
return names;
}
else {
return null;
}
}
}
}

View File

@@ -48,7 +48,6 @@ import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
@@ -100,9 +99,6 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
/** Whether to allow eager class loading even for lazy-init beans */
private boolean allowEagerClassLoading = true;
/** Resolver strategy for method parameter names */
private ParameterNameDiscoverer parameterNameDiscoverer;
/** Resolver to use for checking if a bean definition is an autowire candidate */
private AutowireCandidateResolver autowireCandidateResolver = new SimpleAutowireCandidateResolver();
@@ -177,17 +173,6 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
this.allowEagerClassLoading = allowEagerClassLoading;
}
/**
* Set the ParameterNameDiscoverer to use for resolving method parameter
* names if needed (e.g. for default qualifier values on autowired methods).
* <p>Default is none. A typical candidate is
* {@link org.springframework.core.LocalVariableTableParameterNameDiscoverer},
* which implies an ASM dependency and hence isn't set as the default.
*/
public void setParameterNameDiscoverer(ParameterNameDiscoverer parameterNameDiscoverer) {
this.parameterNameDiscoverer = parameterNameDiscoverer;
}
/**
* Set a custom autowire candidate resolver for this BeanFactory to use
* when deciding whether a bean definition should be considered as a
@@ -452,7 +437,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
protected boolean isAutowireCandidate(String beanName, RootBeanDefinition mbd, DependencyDescriptor descriptor) {
resolveBeanClass(mbd, beanName);
if (mbd.isFactoryMethodUnique && mbd.resolvedConstructorOrFactoryMethod == null) {
new ConstructorResolver(this, null, null, null).resolveFactoryMethodIfPossible(mbd);
new ConstructorResolver(this).resolveFactoryMethodIfPossible(mbd);
}
return getAutowireCandidateResolver().isAutowireCandidate(
new BeanDefinitionHolder(mbd, beanName, getAliases(beanName)), descriptor);
@@ -622,8 +607,8 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
public Object resolveDependency(DependencyDescriptor descriptor, String beanName,
Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {
descriptor.initParameterNameDiscovery(this.parameterNameDiscoverer);
Class type = descriptor.getDependencyType();
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
Class<?> type = descriptor.getDependencyType();
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {

View File

@@ -756,6 +756,7 @@ public class BeanDefinitionParserDelegate {
public void parseConstructorArgElement(Element ele, BeanDefinition bd) {
String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE);
String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
if (StringUtils.hasLength(indexAttr)) {
try {
int index = Integer.parseInt(indexAttr);
@@ -770,6 +771,9 @@ public class BeanDefinitionParserDelegate {
if (StringUtils.hasLength(typeAttr)) {
valueHolder.setType(typeAttr);
}
if (StringUtils.hasLength(nameAttr)) {
valueHolder.setName(nameAttr);
}
valueHolder.setSource(extractSource(ele));
bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder);
}
@@ -790,6 +794,9 @@ public class BeanDefinitionParserDelegate {
if (StringUtils.hasLength(typeAttr)) {
valueHolder.setType(typeAttr);
}
if (StringUtils.hasLength(nameAttr)) {
valueHolder.setName(nameAttr);
}
valueHolder.setSource(extractSource(ele));
bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* Copyright 2002-2009 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.
@@ -168,15 +168,13 @@ public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocume
// Resolve system properties: e.g. "${user.dir}"
location = SystemPropertyUtils.resolvePlaceholders(location);
Set<Resource> actualResources = new LinkedHashSet<Resource>(4);
if (ResourcePatternUtils.isUrl(location)) {
try {
Set<Resource> actualResources = new LinkedHashSet<Resource> (4);
int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
if (logger.isDebugEnabled()) {
logger.debug("Imported " + importCount + " bean definitions from URL location [" + location + "]");
}
Resource[] actResArray = actualResources.toArray(new Resource[actualResources.size()]);
getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error(
@@ -186,22 +184,23 @@ public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocume
else {
// No URL -> considering resource location as relative to the current file.
try {
Resource relativeResource = getReaderContext().getResource().createRelative(location);
int importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
String baseLocation = getReaderContext().getResource().getURL().toString();
int importCount = getReaderContext().getReader().loadBeanDefinitions(
StringUtils.applyRelativePath(baseLocation, location), actualResources);
if (logger.isDebugEnabled()) {
logger.debug("Imported " + importCount + " bean definitions from relative location [" + location + "]");
}
getReaderContext().fireImportProcessed(location, new Resource[] {relativeResource}, extractSource(ele));
}
catch (IOException ex) {
getReaderContext().error(
"Invalid relative resource location [" + location + "] to import bean definitions from", ele, ex);
getReaderContext().error("Failed to resolve current resource location", ele, ex);
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error(
"Failed to import bean definitions from relative location [" + location + "]", ele, ex);
getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]",
ele, ex);
}
}
Resource[] actResArray = actualResources.toArray(new Resource[actualResources.size()]);
getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));
}
/**