Merge branch '2.0.x'

pull/13797/merge
Stephane Nicoll 6 years ago
commit 8bf22db9c3

@ -26,7 +26,10 @@ import java.util.Set;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport; import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;
import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport.ConditionAndOutcome; import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport.ConditionAndOutcome;
@ -78,18 +81,27 @@ class NoSuchBeanDefinitionFailureAnalyzer
} }
List<AutoConfigurationResult> autoConfigurationResults = getAutoConfigurationResults( List<AutoConfigurationResult> autoConfigurationResults = getAutoConfigurationResults(
cause); cause);
List<UserConfigurationResult> userConfigurationResults = getUserConfigurationResults(
cause);
StringBuilder message = new StringBuilder(); StringBuilder message = new StringBuilder();
message.append(String.format("%s required %s that could not be found.%n", message.append(String.format("%s required %s that could not be found.%n",
(description != null ? description : "A component"), (description != null ? description : "A component"),
getBeanDescription(cause))); getBeanDescription(cause)));
if (!autoConfigurationResults.isEmpty()) { if (!autoConfigurationResults.isEmpty()) {
for (AutoConfigurationResult provider : autoConfigurationResults) { for (AutoConfigurationResult result : autoConfigurationResults) {
message.append(String.format("\t- %s%n", provider)); message.append(String.format("\t- %s%n", result));
}
}
if (!userConfigurationResults.isEmpty()) {
for (UserConfigurationResult result : userConfigurationResults) {
message.append(String.format("\t- %s%n", result));
} }
} }
String action = String.format("Consider %s %s in your configuration.", String action = String.format("Consider %s %s in your configuration.",
(!autoConfigurationResults.isEmpty() (!autoConfigurationResults.isEmpty()
? "revisiting the conditions above or defining" : "defining"), || !userConfigurationResults.isEmpty()
? "revisiting the entries above or defining"
: "defining"),
getBeanDescription(cause)); getBeanDescription(cause));
return new FailureAnalysis(message.toString(), action, cause); return new FailureAnalysis(message.toString(), action, cause);
} }
@ -122,6 +134,30 @@ class NoSuchBeanDefinitionFailureAnalyzer
return results; return results;
} }
private List<UserConfigurationResult> getUserConfigurationResults(
NoSuchBeanDefinitionException cause) {
List<UserConfigurationResult> results = new ArrayList<>();
ResolvableType type = cause.getResolvableType();
if (type != null) {
for (String beanName : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, cause.getResolvableType())) {
boolean nullBean = this.beanFactory.getBean(beanName).equals(null);
results.add(new UserConfigurationResult(
getFactoryMethodMetadata(beanName), nullBean));
}
}
return results;
}
private MethodMetadata getFactoryMethodMetadata(String beanName) {
BeanDefinition beanDefinition = this.beanFactory.getBeanDefinition(beanName);
if (beanDefinition instanceof AnnotatedBeanDefinition) {
return ((AnnotatedBeanDefinition) beanDefinition).getFactoryMethodMetadata();
}
return null;
}
private void collectReportedConditionOutcomes(NoSuchBeanDefinitionException cause, private void collectReportedConditionOutcomes(NoSuchBeanDefinitionException cause,
List<AutoConfigurationResult> results) { List<AutoConfigurationResult> results) {
this.report.getConditionAndOutcomesBySource().forEach( this.report.getConditionAndOutcomesBySource().forEach(
@ -296,4 +332,31 @@ class NoSuchBeanDefinitionFailureAnalyzer
} }
private static class UserConfigurationResult {
private final MethodMetadata methodMetadata;
private final boolean nullBean;
UserConfigurationResult(MethodMetadata methodMetadata, boolean nullBean) {
this.methodMetadata = methodMetadata;
this.nullBean = nullBean;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("User-defined bean");
if (this.methodMetadata != null) {
sb.append(String.format(" method '%s' in '%s'",
this.methodMetadata.getMethodName(), ClassUtils.getShortName(
this.methodMetadata.getDeclaringClassName())));
}
if (this.nullBean) {
sb.append(" ignored as the bean value is null");
}
return sb.toString();
}
}
} }

@ -184,6 +184,17 @@ public class NoSuchBeanDefinitionFailureAnalyzerTests {
assertActionMissingName(analysis, "test-string"); assertActionMissingName(analysis, "test-string");
} }
@Test
public void failureAnalysisForNullBeanByType() {
FailureAnalysis analysis = analyzeFailure(
createFailure(StringNullBeanConfiguration.class));
assertDescriptionConstructorMissingType(analysis, StringHandler.class, 0,
String.class);
assertUserDefinedBean(analysis, "as the bean value is null",
TestNullBeanConfiguration.class, "string");
assertActionMissingType(analysis, String.class);
}
private void assertDescriptionConstructorMissingType(FailureAnalysis analysis, private void assertDescriptionConstructorMissingType(FailureAnalysis analysis,
Class<?> component, int index, Class<?> type) { Class<?> component, int index, Class<?> type) {
String expected = String.format( String expected = String.format(
@ -195,14 +206,14 @@ public class NoSuchBeanDefinitionFailureAnalyzerTests {
private void assertActionMissingType(FailureAnalysis analysis, Class<?> type) { private void assertActionMissingType(FailureAnalysis analysis, Class<?> type) {
assertThat(analysis.getAction()).startsWith(String.format( assertThat(analysis.getAction()).startsWith(String.format(
"Consider revisiting the conditions above or defining a bean of type '%s' " "Consider revisiting the entries above or defining a bean of type '%s' "
+ "in your configuration.", + "in your configuration.",
type.getName())); type.getName()));
} }
private void assertActionMissingName(FailureAnalysis analysis, String name) { private void assertActionMissingName(FailureAnalysis analysis, String name) {
assertThat(analysis.getAction()).startsWith(String.format( assertThat(analysis.getAction()).startsWith(String.format(
"Consider revisiting the conditions above or defining a bean named '%s' " "Consider revisiting the entries above or defining a bean named '%s' "
+ "in your configuration.", + "in your configuration.",
name)); name));
} }
@ -223,6 +234,14 @@ public class NoSuchBeanDefinitionFailureAnalyzerTests {
assertThat(analysis.getDescription()).contains(description); assertThat(analysis.getDescription()).contains(description);
} }
private void assertUserDefinedBean(FailureAnalysis analysis, String description,
Class<?> target, String methodName) {
String expected = String.format("User-defined bean method '%s' in '%s' ignored",
methodName, ClassUtils.getShortName(target));
assertThat(analysis.getDescription()).contains(expected);
assertThat(analysis.getDescription()).contains(description);
}
private static void addExclusions(NoSuchBeanDefinitionFailureAnalyzer analyzer, private static void addExclusions(NoSuchBeanDefinitionFailureAnalyzer analyzer,
Class<?>... classes) { Class<?>... classes) {
ConditionEvaluationReport report = (ConditionEvaluationReport) new DirectFieldAccessor( ConditionEvaluationReport report = (ConditionEvaluationReport) new DirectFieldAccessor(
@ -305,6 +324,13 @@ public class NoSuchBeanDefinitionFailureAnalyzerTests {
} }
@Configuration
@ImportAutoConfiguration(TestNullBeanConfiguration.class)
@Import(StringHandler.class)
protected static class StringNullBeanConfiguration {
}
@Configuration @Configuration
public static class TestPropertyAutoConfiguration { public static class TestPropertyAutoConfiguration {
@ -344,6 +370,16 @@ public class NoSuchBeanDefinitionFailureAnalyzerTests {
} }
@Configuration
public static class TestNullBeanConfiguration {
@Bean
public String string() {
return null;
}
}
protected static class StringHandler { protected static class StringHandler {
public StringHandler(String foo) { public StringHandler(String foo) {

Loading…
Cancel
Save