Browse Source

Defensive handling of exceptions during factory method type checking

Also using ClassUtils.forName in AutowireUtils now in order to accept all common class name formats.

Issue: SPR-11034
pull/395/head
Juergen Hoeller 13 years ago
parent
commit
8c1767e223
  1. 55
      spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java
  2. 9
      spring-beans/src/main/java/org/springframework/beans/factory/support/AutowireUtils.java
  3. 17
      spring-beans/src/test/java/org/springframework/beans/factory/support/BeanFactoryGenericsTests.java

55
spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java

@ -667,33 +667,40 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
factoryMethod.getParameterTypes().length >= minNrOfArgs) { factoryMethod.getParameterTypes().length >= minNrOfArgs) {
// No declared type variables to inspect, so just process the standard return type. // No declared type variables to inspect, so just process the standard return type.
if (factoryMethod.getTypeParameters().length > 0) { if (factoryMethod.getTypeParameters().length > 0) {
// Fully resolve parameter names and argument values. try {
Class<?>[] paramTypes = factoryMethod.getParameterTypes(); // Fully resolve parameter names and argument values.
String[] paramNames = null; Class<?>[] paramTypes = factoryMethod.getParameterTypes();
ParameterNameDiscoverer pnd = getParameterNameDiscoverer(); String[] paramNames = null;
if (pnd != null) { ParameterNameDiscoverer pnd = getParameterNameDiscoverer();
paramNames = pnd.getParameterNames(factoryMethod); if (pnd != null) {
} paramNames = pnd.getParameterNames(factoryMethod);
ConstructorArgumentValues cav = mbd.getConstructorArgumentValues(); }
Set<ConstructorArgumentValues.ValueHolder> usedValueHolders = ConstructorArgumentValues cav = mbd.getConstructorArgumentValues();
new HashSet<ConstructorArgumentValues.ValueHolder>(paramTypes.length); Set<ConstructorArgumentValues.ValueHolder> usedValueHolders =
Object[] args = new Object[paramTypes.length]; new HashSet<ConstructorArgumentValues.ValueHolder>(paramTypes.length);
for (int i = 0; i < args.length; i++) { Object[] args = new Object[paramTypes.length];
ConstructorArgumentValues.ValueHolder valueHolder = cav.getArgumentValue( for (int i = 0; i < args.length; i++) {
i, paramTypes[i], (paramNames != null ? paramNames[i] : null), usedValueHolders); ConstructorArgumentValues.ValueHolder valueHolder = cav.getArgumentValue(
if (valueHolder == null) { i, paramTypes[i], (paramNames != null ? paramNames[i] : null), usedValueHolders);
valueHolder = cav.getGenericArgumentValue(null, null, usedValueHolders); if (valueHolder == null) {
valueHolder = cav.getGenericArgumentValue(null, null, usedValueHolders);
}
if (valueHolder != null) {
args[i] = valueHolder.getValue();
usedValueHolders.add(valueHolder);
}
} }
if (valueHolder != null) { Class<?> returnType = AutowireUtils.resolveReturnTypeForFactoryMethod(
args[i] = valueHolder.getValue(); factoryMethod, args, getBeanClassLoader());
usedValueHolders.add(valueHolder); if (returnType != null) {
cache = true;
returnTypes.add(returnType);
} }
} }
Class<?> returnType = AutowireUtils.resolveReturnTypeForFactoryMethod( catch (Throwable ex) {
factoryMethod, args, getBeanClassLoader()); if (logger.isDebugEnabled()) {
if (returnType != null) { logger.debug("Failed to resolve generic return type for factory method: " + ex);
cache = true; }
returnTypes.add(returnType);
} }
} }
else { else {

9
spring-beans/src/main/java/org/springframework/beans/factory/support/AutowireUtils.java

@ -223,7 +223,8 @@ abstract class AutowireUtils {
return typedValue.resolveTargetType(classLoader); return typedValue.resolveTargetType(classLoader);
} }
catch (ClassNotFoundException ex) { catch (ClassNotFoundException ex) {
throw new IllegalStateException("Failed to resolve typed value", ex); throw new IllegalStateException("Failed to resolve value type [" +
typedValue.getTargetTypeName() + "] for factory method argument", ex);
} }
} }
// Only consider argument type if it is a simple value... // Only consider argument type if it is a simple value...
@ -254,11 +255,11 @@ abstract class AutowireUtils {
} }
if (className != null) { if (className != null) {
try { try {
return classLoader.loadClass(className); return ClassUtils.forName(className, classLoader);
} }
catch (ClassNotFoundException ex) { catch (ClassNotFoundException ex) {
throw new IllegalStateException( throw new IllegalStateException("Could not resolve class name [" + arg +
"Could not resolve specified class name argument [" + arg + "]", ex); "] for factory method argument", ex);
} }
} }
// Consider adding logic to determine the class of the typeArg, if possible. // Consider adding logic to determine the class of the typeArg, if possible.

17
spring-beans/src/test/java/org/springframework/beans/factory/support/BeanFactoryGenericsTests.java

@ -735,6 +735,23 @@ public class BeanFactoryGenericsTests {
assertEquals(1, beans.size()); assertEquals(1, beans.size());
} }
@Test
public void parameterizedInstanceFactoryMethodWithInvalidClassName() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
RootBeanDefinition rbd = new RootBeanDefinition(MocksControl.class);
bf.registerBeanDefinition("mocksControl", rbd);
rbd = new RootBeanDefinition();
rbd.setFactoryBeanName("mocksControl");
rbd.setFactoryMethodName("createMock");
rbd.getConstructorArgumentValues().addGenericArgumentValue("x");
bf.registerBeanDefinition("mock", rbd);
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
assertEquals(0, beans.size());
}
@Test @Test
public void parameterizedInstanceFactoryMethodWithIndexedArgument() { public void parameterizedInstanceFactoryMethodWithIndexedArgument() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); DefaultListableBeanFactory bf = new DefaultListableBeanFactory();

Loading…
Cancel
Save