diff --git a/spring-boot-dependencies/pom.xml b/spring-boot-dependencies/pom.xml
index 81fb3587a0e..b2c01dce5a2 100644
--- a/spring-boot-dependencies/pom.xml
+++ b/spring-boot-dependencies/pom.xml
@@ -139,7 +139,7 @@
1.17
5.5.0
1.0-groovy-2.4
- 4.3.0.RC1
+ 4.3.0.BUILD-SNAPSHOT
1.6.0.M2
1.2.2.RELEASE
3.0.6.RELEASE
diff --git a/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/NoUniqueBeanDefinitionExceptionFailureAnalyzer.java b/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/NoUniqueBeanDefinitionFailureAnalyzer.java
similarity index 73%
rename from spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/NoUniqueBeanDefinitionExceptionFailureAnalyzer.java
rename to spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/NoUniqueBeanDefinitionFailureAnalyzer.java
index e6d795bfbd1..61cbfdcd40a 100644
--- a/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/NoUniqueBeanDefinitionExceptionFailureAnalyzer.java
+++ b/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/NoUniqueBeanDefinitionFailureAnalyzer.java
@@ -16,6 +16,7 @@
package org.springframework.boot.diagnostics.analyzer;
+import org.springframework.beans.BeanInstantiationException;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
@@ -28,6 +29,7 @@ import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.boot.diagnostics.AbstractFailureAnalyzer;
import org.springframework.boot.diagnostics.FailureAnalysis;
import org.springframework.util.Assert;
+import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
/**
@@ -36,7 +38,7 @@ import org.springframework.util.StringUtils;
*
* @author Andy Wilkinson
*/
-class NoUniqueBeanDefinitionExceptionFailureAnalyzer
+class NoUniqueBeanDefinitionFailureAnalyzer
extends AbstractFailureAnalyzer
implements BeanFactoryAware {
@@ -51,9 +53,8 @@ class NoUniqueBeanDefinitionExceptionFailureAnalyzer
@Override
protected FailureAnalysis analyze(Throwable rootFailure,
NoUniqueBeanDefinitionException cause) {
- UnsatisfiedDependencyException unsatisfiedDependency = findUnsatisfiedDependencyException(
- rootFailure);
- if (unsatisfiedDependency == null) {
+ String consumerDescription = getConsumerDescription(rootFailure);
+ if (consumerDescription == null) {
return null;
}
String[] beanNames = extractBeanNames(cause);
@@ -62,7 +63,7 @@ class NoUniqueBeanDefinitionExceptionFailureAnalyzer
}
StringBuilder message = new StringBuilder();
message.append(String.format("%s required a single bean, but %d were found:%n",
- getConsumerDescription(unsatisfiedDependency), beanNames.length));
+ consumerDescription, beanNames.length));
for (String beanName : beanNames) {
try {
BeanDefinition beanDefinition = this.beanFactory
@@ -90,13 +91,37 @@ class NoUniqueBeanDefinitionExceptionFailureAnalyzer
cause);
}
+ private String getConsumerDescription(Throwable ex) {
+ UnsatisfiedDependencyException unsatisfiedDependency = findUnsatisfiedDependencyException(
+ ex);
+ if (unsatisfiedDependency != null) {
+ return getConsumerDescription(unsatisfiedDependency);
+ }
+ BeanInstantiationException beanInstantiationException = findBeanInstantiationException(
+ ex);
+ if (beanInstantiationException != null) {
+ return getConsumerDescription(beanInstantiationException);
+ }
+ return null;
+ }
+
private UnsatisfiedDependencyException findUnsatisfiedDependencyException(
Throwable root) {
+ return findMostNestedCause(root, UnsatisfiedDependencyException.class);
+ }
+
+ private BeanInstantiationException findBeanInstantiationException(Throwable root) {
+ return findMostNestedCause(root, BeanInstantiationException.class);
+ }
+
+ @SuppressWarnings("unchecked")
+ private T findMostNestedCause(Throwable root,
+ Class causeType) {
Throwable candidate = root;
- UnsatisfiedDependencyException mostNestedMatch = null;
+ T mostNestedMatch = null;
while (candidate != null) {
- if (candidate instanceof UnsatisfiedDependencyException) {
- mostNestedMatch = (UnsatisfiedDependencyException) candidate;
+ if (causeType.isAssignableFrom(candidate.getClass())) {
+ mostNestedMatch = (T) candidate;
}
candidate = candidate.getCause();
}
@@ -107,7 +132,7 @@ class NoUniqueBeanDefinitionExceptionFailureAnalyzer
InjectionPoint injectionPoint = ex.getInjectionPoint();
if (injectionPoint != null) {
if (injectionPoint.getField() != null) {
- return String.format("Field '%s' in %s",
+ return String.format("Field %s in %s",
injectionPoint.getField().getName(),
injectionPoint.getField().getDeclaringClass().getName());
}
@@ -118,7 +143,7 @@ class NoUniqueBeanDefinitionExceptionFailureAnalyzer
injectionPoint.getMethodParameter().getDeclaringClass()
.getName());
}
- return String.format("Parameter %d of method '%s' in %s",
+ return String.format("Parameter %d of method %s in %s",
injectionPoint.getMethodParameter().getParameterIndex(),
injectionPoint.getMethodParameter().getMethod().getName(),
injectionPoint.getMethodParameter().getDeclaringClass()
@@ -128,6 +153,18 @@ class NoUniqueBeanDefinitionExceptionFailureAnalyzer
return ex.getResourceDescription();
}
+ private String getConsumerDescription(BeanInstantiationException ex) {
+ if (ex.getConstructingMethod() != null) {
+ return String.format("Method %s in %s", ex.getConstructingMethod().getName(),
+ ex.getConstructingMethod().getDeclaringClass().getName());
+ }
+ if (ex.getConstructor() != null) {
+ return String.format("Constructor in %s", ClassUtils
+ .getUserClass(ex.getConstructor().getDeclaringClass()).getName());
+ }
+ return ex.getBeanClass().getName();
+ }
+
private String[] extractBeanNames(NoUniqueBeanDefinitionException cause) {
if (cause.getMessage().indexOf("but found") > -1) {
return StringUtils.commaDelimitedListToStringArray(cause.getMessage()
diff --git a/spring-boot/src/main/resources/META-INF/spring.factories b/spring-boot/src/main/resources/META-INF/spring.factories
index 0eb778ab8b2..ca7babae93f 100644
--- a/spring-boot/src/main/resources/META-INF/spring.factories
+++ b/spring-boot/src/main/resources/META-INF/spring.factories
@@ -33,8 +33,10 @@ org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor
# Failure Analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=\
+org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\
+org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\
-org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer
+org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer,
# FailureAnalysisReporters
org.springframework.boot.diagnostics.FailureAnalysisReporter=\
diff --git a/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/NoUniqueBeanDefinitionExceptionFailureAnalyzerTests.java b/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/NoUniqueBeanDefinitionFailureAnalyzerTests.java
similarity index 64%
rename from spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/NoUniqueBeanDefinitionExceptionFailureAnalyzerTests.java
rename to spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/NoUniqueBeanDefinitionFailureAnalyzerTests.java
index 24941f2c39f..036189f6339 100644
--- a/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/NoUniqueBeanDefinitionExceptionFailureAnalyzerTests.java
+++ b/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/NoUniqueBeanDefinitionFailureAnalyzerTests.java
@@ -18,7 +18,8 @@ package org.springframework.boot.diagnostics.analyzer;
import org.junit.Test;
-import org.springframework.beans.factory.UnsatisfiedDependencyException;
+import org.springframework.beans.factory.BeanCreationException;
+import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.diagnostics.FailureAnalysis;
import org.springframework.boot.diagnostics.analyzer.nounique.TestBean;
@@ -32,21 +33,20 @@ import org.springframework.context.annotation.ImportResource;
import static org.assertj.core.api.Assertions.assertThat;
/**
- * Tests for {@link NoUniqueBeanDefinitionExceptionFailureAnalyzer}.
+ * Tests for {@link NoUniqueBeanDefinitionFailureAnalyzer}.
*
* @author Andy Wilkinson
*/
-public class NoUniqueBeanDefinitionExceptionFailureAnalyzerTests {
+public class NoUniqueBeanDefinitionFailureAnalyzerTests {
- private final NoUniqueBeanDefinitionExceptionFailureAnalyzer analyzer = new NoUniqueBeanDefinitionExceptionFailureAnalyzer();
+ private final NoUniqueBeanDefinitionFailureAnalyzer analyzer = new NoUniqueBeanDefinitionFailureAnalyzer();
@Test
public void failureAnalysisForFieldConsumer() {
FailureAnalysis failureAnalysis = analyzeFailure(
createFailure(FieldConsumer.class));
- System.out.println(failureAnalysis.getDescription());
assertThat(failureAnalysis.getDescription())
- .startsWith("Field 'testBean' in " + FieldConsumer.class.getName()
+ .startsWith("Field testBean in " + FieldConsumer.class.getName()
+ " required a single bean, but 6 were found:");
assertFoundBeans(failureAnalysis);
}
@@ -55,9 +55,28 @@ public class NoUniqueBeanDefinitionExceptionFailureAnalyzerTests {
public void failureAnalysisForMethodConsumer() {
FailureAnalysis failureAnalysis = analyzeFailure(
createFailure(MethodConsumer.class));
- System.out.println(failureAnalysis.getDescription());
assertThat(failureAnalysis.getDescription()).startsWith(
- "Parameter 0 of method 'consumer' in " + MethodConsumer.class.getName()
+ "Parameter 0 of method consumer in " + MethodConsumer.class.getName()
+ + " required a single bean, but 6 were found:");
+ assertFoundBeans(failureAnalysis);
+ }
+
+ @Test
+ public void failureAnalysisForConstructorConsumer() {
+ FailureAnalysis failureAnalysis = analyzeFailure(
+ createFailure(ConstructorConsumer.class));
+ assertThat(failureAnalysis.getDescription()).startsWith(
+ "Parameter 0 of constructor in " + ConstructorConsumer.class.getName()
+ + " required a single bean, but 6 were found:");
+ assertFoundBeans(failureAnalysis);
+ }
+
+ @Test
+ public void failureAnalysisForObjectProviderMethodConsumer() {
+ FailureAnalysis failureAnalysis = analyzeFailure(
+ createFailure(ObjectProviderMethodConsumer.class));
+ assertThat(failureAnalysis.getDescription()).startsWith(
+ "Method consumer in " + ObjectProviderMethodConsumer.class.getName()
+ " required a single bean, but 6 were found:");
assertFoundBeans(failureAnalysis);
}
@@ -66,14 +85,23 @@ public class NoUniqueBeanDefinitionExceptionFailureAnalyzerTests {
public void failureAnalysisForXmlConsumer() {
FailureAnalysis failureAnalysis = analyzeFailure(
createFailure(XmlConsumer.class));
- System.out.println(failureAnalysis.getDescription());
assertThat(failureAnalysis.getDescription()).startsWith(
"Parameter 0 of constructor in " + TestBeanConsumer.class.getName()
+ " required a single bean, but 6 were found:");
assertFoundBeans(failureAnalysis);
}
- private UnsatisfiedDependencyException createFailure(Class> consumer) {
+ @Test
+ public void failureAnalysisForObjectProviderConstructorConsumer() {
+ FailureAnalysis failureAnalysis = analyzeFailure(
+ createFailure(ObjectProviderConstructorConsumer.class));
+ assertThat(failureAnalysis.getDescription()).startsWith(
+ "Constructor in " + ObjectProviderConstructorConsumer.class.getName()
+ + " required a single bean, but 6 were found:");
+ assertFoundBeans(failureAnalysis);
+ }
+
+ private BeanCreationException createFailure(Class> consumer) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(DuplicateBeansProducer.class, consumer);
context.setParent(new AnnotationConfigApplicationContext(ParentProducer.class));
@@ -81,7 +109,7 @@ public class NoUniqueBeanDefinitionExceptionFailureAnalyzerTests {
context.refresh();
return null;
}
- catch (UnsatisfiedDependencyException ex) {
+ catch (BeanCreationException ex) {
this.analyzer.setBeanFactory(context.getBeanFactory());
return ex;
}
@@ -90,7 +118,7 @@ public class NoUniqueBeanDefinitionExceptionFailureAnalyzerTests {
}
}
- private FailureAnalysis analyzeFailure(UnsatisfiedDependencyException failure) {
+ private FailureAnalysis analyzeFailure(BeanCreationException failure) {
return this.analyzer.analyze(failure);
}
@@ -144,6 +172,24 @@ public class NoUniqueBeanDefinitionExceptionFailureAnalyzerTests {
}
+ @Configuration
+ static class ObjectProviderConstructorConsumer {
+
+ ObjectProviderConstructorConsumer(ObjectProvider objectProvider) {
+ objectProvider.getIfAvailable();
+ }
+
+ }
+
+ @Configuration
+ static class ConstructorConsumer {
+
+ ConstructorConsumer(TestBean testBean) {
+
+ }
+
+ }
+
@Configuration
static class MethodConsumer {
@@ -154,6 +200,17 @@ public class NoUniqueBeanDefinitionExceptionFailureAnalyzerTests {
}
+ @Configuration
+ static class ObjectProviderMethodConsumer {
+
+ @Bean
+ String consumer(ObjectProvider testBeanProvider) {
+ testBeanProvider.getIfAvailable();
+ return "foo";
+ }
+
+ }
+
@Configuration
@ImportResource("/org/springframework/boot/diagnostics/analyzer/nounique/consumer.xml")
static class XmlConsumer {