Skip to content

Commit d55af2b

Browse files
committed
Consistent throwing of last UnsatisfiedDependencyException if available and no constructor resolved
Issue: SPR-12543
1 parent cae217d commit d55af2b

File tree

2 files changed

+49
-18
lines changed

2 files changed

+49
-18
lines changed

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

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ public BeanWrapper autowireConstructor(final String beanName, final RootBeanDefi
157157
AutowireUtils.sortConstructors(candidates);
158158
int minTypeDiffWeight = Integer.MAX_VALUE;
159159
Set<Constructor<?>> ambiguousConstructors = null;
160-
List<Exception> causes = null;
160+
LinkedList<UnsatisfiedDependencyException> causes = null;
161161

162162
for (int i = 0; i < candidates.length; i++) {
163163
Constructor<?> candidate = candidates[i];
@@ -190,22 +190,12 @@ public BeanWrapper autowireConstructor(final String beanName, final RootBeanDefi
190190
this.beanFactory.logger.trace(
191191
"Ignoring constructor [" + candidate + "] of bean '" + beanName + "': " + ex);
192192
}
193-
if (i == candidates.length - 1 && constructorToUse == null) {
194-
if (causes != null) {
195-
for (Exception cause : causes) {
196-
this.beanFactory.onSuppressedException(cause);
197-
}
198-
}
199-
throw ex;
200-
}
201-
else {
202-
// Swallow and try next constructor.
203-
if (causes == null) {
204-
causes = new LinkedList<Exception>();
205-
}
206-
causes.add(ex);
207-
continue;
193+
// Swallow and try next constructor.
194+
if (causes == null) {
195+
causes = new LinkedList<UnsatisfiedDependencyException>();
208196
}
197+
causes.add(ex);
198+
continue;
209199
}
210200
}
211201
else {
@@ -236,6 +226,13 @@ else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
236226
}
237227

238228
if (constructorToUse == null) {
229+
if (causes != null) {
230+
UnsatisfiedDependencyException ex = causes.removeLast();
231+
for (Exception cause : causes) {
232+
this.beanFactory.onSuppressedException(cause);
233+
}
234+
throw ex;
235+
}
239236
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
240237
"Could not resolve matching constructor " +
241238
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)");

spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2023,6 +2023,30 @@ public void testAvoidCircularReferenceThroughAutowiring() {
20232023
lbf.preInstantiateSingletons();
20242024
}
20252025

2026+
@Test
2027+
public void testConstructorDependencyWithClassResolution() {
2028+
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
2029+
RootBeanDefinition bd = new RootBeanDefinition(ConstructorDependencyWithClassResolution.class);
2030+
bd.getConstructorArgumentValues().addGenericArgumentValue("java.lang.String");
2031+
lbf.registerBeanDefinition("test", bd);
2032+
lbf.preInstantiateSingletons();
2033+
}
2034+
2035+
@Test
2036+
public void testConstructorDependencyWithUnresolvableClass() {
2037+
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
2038+
RootBeanDefinition bd = new RootBeanDefinition(ConstructorDependencyWithClassResolution.class);
2039+
bd.getConstructorArgumentValues().addGenericArgumentValue("java.lang.Strin");
2040+
lbf.registerBeanDefinition("test", bd);
2041+
try {
2042+
lbf.preInstantiateSingletons();
2043+
fail("Should have thrown UnsatisfiedDependencyException");
2044+
}
2045+
catch (UnsatisfiedDependencyException expected) {
2046+
assertTrue(expected.toString().contains("java.lang.Strin"));
2047+
}
2048+
}
2049+
20262050
@Test
20272051
public void testBeanDefinitionWithInterface() {
20282052
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
@@ -2033,7 +2057,7 @@ public void testBeanDefinitionWithInterface() {
20332057
}
20342058
catch (BeanCreationException ex) {
20352059
assertEquals("test", ex.getBeanName());
2036-
assertTrue(ex.getMessage().toLowerCase().indexOf("interface") != -1);
2060+
assertTrue(ex.getMessage().toLowerCase().contains("interface"));
20372061
}
20382062
}
20392063

@@ -2047,7 +2071,7 @@ public void testBeanDefinitionWithAbstractClass() {
20472071
}
20482072
catch (BeanCreationException ex) {
20492073
assertEquals("test", ex.getBeanName());
2050-
assertTrue(ex.getMessage().toLowerCase().indexOf("abstract") != -1);
2074+
assertTrue(ex.getMessage().toLowerCase().contains("abstract"));
20512075
}
20522076
}
20532077

@@ -2739,6 +2763,16 @@ public boolean isSingleton() {
27392763
}
27402764

27412765

2766+
public static class ConstructorDependencyWithClassResolution {
2767+
2768+
public ConstructorDependencyWithClassResolution(Class<?> clazz) {
2769+
}
2770+
2771+
public ConstructorDependencyWithClassResolution() {
2772+
}
2773+
}
2774+
2775+
27422776
public static class BeanWithDisposableBean implements DisposableBean {
27432777

27442778
private static boolean closed;

0 commit comments

Comments
 (0)