Skip to content

Commit 7e2a214

Browse files
committed
instantiateUsingFactoryMethod avoids NPE and reports argument types in case of explicitArgs and resolved generic arguments as well
Issue: SPR-11517 (cherry picked from commit ad31777)
1 parent 4c9c763 commit 7e2a214

File tree

3 files changed

+55
-15
lines changed

3 files changed

+55
-15
lines changed

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

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -530,24 +530,30 @@ else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight &&
530530
}
531531

532532
if (factoryMethodToUse == null) {
533-
boolean hasArgs = (resolvedValues.getArgumentCount() > 0);
534-
String argDesc = "";
535-
if (hasArgs) {
536-
List<String> argTypes = new ArrayList<String>();
537-
for (ValueHolder value : resolvedValues.getIndexedArgumentValues().values()) {
538-
String argType = (value.getType() != null ?
539-
ClassUtils.getShortName(value.getType()) : value.getValue().getClass().getSimpleName());
533+
List<String> argTypes = new ArrayList<String>(minNrOfArgs);
534+
if (explicitArgs != null) {
535+
for (Object arg : explicitArgs) {
536+
argTypes.add(arg != null ? arg.getClass().getSimpleName() : "null");
537+
}
538+
}
539+
else {
540+
Set<ValueHolder> valueHolders = new LinkedHashSet<ValueHolder>(resolvedValues.getArgumentCount());
541+
valueHolders.addAll(resolvedValues.getIndexedArgumentValues().values());
542+
valueHolders.addAll(resolvedValues.getGenericArgumentValues());
543+
for (ValueHolder value : valueHolders) {
544+
String argType = (value.getType() != null ? ClassUtils.getShortName(value.getType()) :
545+
(value.getValue() != null ? value.getValue().getClass().getSimpleName() : "null"));
540546
argTypes.add(argType);
541547
}
542-
argDesc = StringUtils.collectionToCommaDelimitedString(argTypes);
543548
}
549+
String argDesc = StringUtils.collectionToCommaDelimitedString(argTypes);
544550
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
545551
"No matching factory method found: " +
546552
(mbd.getFactoryBeanName() != null ?
547553
"factory bean '" + mbd.getFactoryBeanName() + "'; " : "") +
548554
"factory method '" + mbd.getFactoryMethodName() + "(" + argDesc + ")'. " +
549555
"Check that a method with the specified name " +
550-
(hasArgs ? "and arguments " : "") +
556+
(minNrOfArgs > 0 ? "and arguments " : "") +
551557
"exists and that it is " +
552558
(isStatic ? "static" : "non-static") + ".");
553559
}

spring-beans/src/test/java/org/springframework/beans/factory/xml/FactoryMethodTests.java

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2013 the original author or authors.
2+
* Copyright 2002-2014 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -21,7 +21,6 @@
2121
import java.util.List;
2222
import java.util.Properties;
2323

24-
import static org.junit.Assert.*;
2524
import org.junit.Test;
2625

2726
import org.springframework.beans.factory.BeanCreationException;
@@ -30,6 +29,8 @@
3029
import org.springframework.core.io.ClassPathResource;
3130
import org.springframework.tests.sample.beans.TestBean;
3231

32+
import static org.junit.Assert.*;
33+
3334
/**
3435
* @author Juergen Hoeller
3536
* @author Chris Beams
@@ -259,6 +260,34 @@ public void testFactoryMethodNoMatchingStaticMethod() {
259260
}
260261
}
261262

263+
@Test
264+
public void testNonExistingFactoryMethod() {
265+
DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
266+
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf);
267+
reader.loadBeanDefinitions(new ClassPathResource("factory-methods.xml", getClass()));
268+
try {
269+
xbf.getBean("invalidPrototype");
270+
fail("Should have thrown BeanCreationException");
271+
}
272+
catch (BeanCreationException ex) {
273+
assertTrue(ex.getMessage().contains("nonExisting(TestBean)"));
274+
}
275+
}
276+
277+
@Test
278+
public void testFactoryMethodArgumentsForNonExistingMethod() {
279+
DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
280+
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf);
281+
reader.loadBeanDefinitions(new ClassPathResource("factory-methods.xml", getClass()));
282+
try {
283+
xbf.getBean("invalidPrototype", new TestBean());
284+
fail("Should have thrown BeanCreationException");
285+
}
286+
catch (BeanCreationException ex) {
287+
assertTrue(ex.getMessage().contains("nonExisting(TestBean)"));
288+
}
289+
}
290+
262291
@Test
263292
public void testCanSpecifyFactoryMethodArgumentsOnFactoryMethodPrototype() {
264293
DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
@@ -360,7 +389,9 @@ public void testFactoryMethodForJavaMailSession() {
360389

361390
}
362391

392+
363393
class MailSession {
394+
364395
private Properties props;
365396

366397
private MailSession() {
@@ -377,6 +408,6 @@ public static MailSession getDefaultInstance(Properties props) {
377408
}
378409

379410
public Object getProperty(String key) {
380-
return props.get(key);
411+
return this.props.get(key);
381412
}
382413
}

spring-beans/src/test/resources/org/springframework/beans/factory/xml/factory-methods.xml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@
8484
<property name="stringValue"><value>testBeanOnlyPrototypeDISetterString</value></property>
8585
</bean>
8686

87+
<bean id="invalidPrototype" class="org.springframework.beans.factory.xml.FactoryMethods"
88+
factory-method="nonExisting" scope="prototype">
89+
<constructor-arg><ref local="juergen"/></constructor-arg>
90+
</bean>
91+
8792
<bean id="fullPrototype" class="org.springframework.beans.factory.xml.FactoryMethods"
8893
factory-method="newInstance" scope="prototype">
8994
<constructor-arg type="int"><value>27</value></constructor-arg>
@@ -120,9 +125,7 @@
120125
<constructor-arg><value type="java.lang.Integer">33</value></constructor-arg>
121126
</bean>
122127

123-
<bean id="instanceFactoryMethodWithoutArgs"
124-
factory-bean="instanceFactory"
125-
factory-method="defaultInstance"/>
128+
<bean id="instanceFactoryMethodWithoutArgs" factory-bean="instanceFactory" factory-method="defaultInstance"/>
126129

127130
<!-- Unnamed bean with factory-bean declaration -->
128131
<bean factory-bean="instanceFactory" factory-method="defaultInstance"/>

0 commit comments

Comments
 (0)