Skip to content

Commit c8e8d6c

Browse files
committed
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 (cherry picked from commit 8c1767e)
1 parent 094ff88 commit c8e8d6c

File tree

3 files changed

+53
-29
lines changed

3 files changed

+53
-29
lines changed

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

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -643,32 +643,39 @@ protected Class<?> getTypeForFactoryMethod(String beanName, RootBeanDefinition m
643643
factoryMethod.getParameterTypes().length >= minNrOfArgs) {
644644
// No declared type variables to inspect, so just process the standard return type.
645645
if (factoryMethod.getTypeParameters().length > 0) {
646-
// Fully resolve parameter names and argument values.
647-
Class<?>[] paramTypes = factoryMethod.getParameterTypes();
648-
String[] paramNames = null;
649-
ParameterNameDiscoverer pnd = getParameterNameDiscoverer();
650-
if (pnd != null) {
651-
paramNames = pnd.getParameterNames(factoryMethod);
652-
}
653-
ConstructorArgumentValues cav = mbd.getConstructorArgumentValues();
654-
Set<ConstructorArgumentValues.ValueHolder> usedValueHolders =
655-
new HashSet<ConstructorArgumentValues.ValueHolder>(paramTypes.length);
656-
Object[] args = new Object[paramTypes.length];
657-
for (int i = 0; i < args.length; i++) {
658-
ConstructorArgumentValues.ValueHolder valueHolder = cav.getArgumentValue(
659-
i, paramTypes[i], (paramNames != null ? paramNames[i] : null), usedValueHolders);
660-
if (valueHolder == null) {
661-
valueHolder = cav.getGenericArgumentValue(null, null, usedValueHolders);
646+
try {
647+
// Fully resolve parameter names and argument values.
648+
Class<?>[] paramTypes = factoryMethod.getParameterTypes();
649+
String[] paramNames = null;
650+
ParameterNameDiscoverer pnd = getParameterNameDiscoverer();
651+
if (pnd != null) {
652+
paramNames = pnd.getParameterNames(factoryMethod);
653+
}
654+
ConstructorArgumentValues cav = mbd.getConstructorArgumentValues();
655+
Set<ConstructorArgumentValues.ValueHolder> usedValueHolders =
656+
new HashSet<ConstructorArgumentValues.ValueHolder>(paramTypes.length);
657+
Object[] args = new Object[paramTypes.length];
658+
for (int i = 0; i < args.length; i++) {
659+
ConstructorArgumentValues.ValueHolder valueHolder = cav.getArgumentValue(
660+
i, paramTypes[i], (paramNames != null ? paramNames[i] : null), usedValueHolders);
661+
if (valueHolder == null) {
662+
valueHolder = cav.getGenericArgumentValue(null, null, usedValueHolders);
663+
}
664+
if (valueHolder != null) {
665+
args[i] = valueHolder.getValue();
666+
usedValueHolders.add(valueHolder);
667+
}
662668
}
663-
if (valueHolder != null) {
664-
args[i] = valueHolder.getValue();
665-
usedValueHolders.add(valueHolder);
669+
Class<?> returnType = AutowireUtils.resolveReturnTypeForFactoryMethod(
670+
factoryMethod, args, getBeanClassLoader());
671+
if (returnType != null) {
672+
returnTypes.add(returnType);
666673
}
667674
}
668-
Class<?> returnType = AutowireUtils.resolveReturnTypeForFactoryMethod(
669-
factoryMethod, args, getBeanClassLoader());
670-
if (returnType != null) {
671-
returnTypes.add(returnType);
675+
catch (Throwable ex) {
676+
if (logger.isDebugEnabled()) {
677+
logger.debug("Failed to resolve generic return type for factory method: " + ex);
678+
}
672679
}
673680
}
674681
else {

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,8 @@ public static Class<?> resolveReturnTypeForFactoryMethod(Method method, Object[]
221221
return typedValue.resolveTargetType(classLoader);
222222
}
223223
catch (ClassNotFoundException ex) {
224-
throw new IllegalStateException("Failed to resolve typed value", ex);
224+
throw new IllegalStateException("Failed to resolve value type [" +
225+
typedValue.getTargetTypeName() + "] for factory method argument", ex);
225226
}
226227
}
227228
// Only consider argument type if it is a simple value...
@@ -252,11 +253,11 @@ else if (arg instanceof TypedStringValue) {
252253
}
253254
if (className != null) {
254255
try {
255-
return classLoader.loadClass(className);
256+
return ClassUtils.forName(className, classLoader);
256257
}
257258
catch (ClassNotFoundException ex) {
258-
throw new IllegalStateException(
259-
"Could not resolve specified class name argument [" + arg + "]", ex);
259+
throw new IllegalStateException("Could not resolve class name [" + arg +
260+
"] for factory method argument", ex);
260261
}
261262
}
262263
// Consider adding logic to determine the class of the typeArg, if possible.

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

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -660,8 +660,7 @@ public void testSetBean() throws Exception {
660660
* public static <T> T mock(Class<T> classToMock)
661661
* }
662662
* </pre>
663-
* <p>
664-
* See SPR-9493
663+
* <p>See SPR-9493
665664
*/
666665
@Test
667666
public void parameterizedStaticFactoryMethod() {
@@ -736,6 +735,23 @@ public void parameterizedInstanceFactoryMethodWithWrappedClassName() {
736735
assertEquals(1, beans.size());
737736
}
738737

738+
@Test
739+
public void parameterizedInstanceFactoryMethodWithInvalidClassName() {
740+
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
741+
742+
RootBeanDefinition rbd = new RootBeanDefinition(MocksControl.class);
743+
bf.registerBeanDefinition("mocksControl", rbd);
744+
745+
rbd = new RootBeanDefinition();
746+
rbd.setFactoryBeanName("mocksControl");
747+
rbd.setFactoryMethodName("createMock");
748+
rbd.getConstructorArgumentValues().addGenericArgumentValue("x");
749+
bf.registerBeanDefinition("mock", rbd);
750+
751+
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
752+
assertEquals(0, beans.size());
753+
}
754+
739755
@Test
740756
public void parameterizedInstanceFactoryMethodWithIndexedArgument() {
741757
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();

0 commit comments

Comments
 (0)