diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/diagnostics/analyzer/NoSuchBeanDefinitionFailureAnalyzer.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/diagnostics/analyzer/NoSuchBeanDefinitionFailureAnalyzer.java index fac0ee9fcec..b9caf165010 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/diagnostics/analyzer/NoSuchBeanDefinitionFailureAnalyzer.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/diagnostics/analyzer/NoSuchBeanDefinitionFailureAnalyzer.java @@ -35,6 +35,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionOutcome; import org.springframework.boot.diagnostics.FailureAnalysis; import org.springframework.boot.diagnostics.analyzer.AbstractInjectionFailureAnalyzer; import org.springframework.context.annotation.Bean; +import org.springframework.core.ResolvableType; import org.springframework.core.type.MethodMetadata; import org.springframework.core.type.classreading.CachingMetadataReaderFactory; import org.springframework.core.type.classreading.MetadataReader; @@ -94,12 +95,25 @@ class NoSuchBeanDefinitionFailureAnalyzer } private String getBeanDescription(NoSuchBeanDefinitionException cause) { - if (cause.getBeanType() != null) { - return "a bean of type '" + cause.getBeanType().getName() + "'"; + if (cause.getResolvableType() != null) { + Class type = extractBeanType(cause.getResolvableType()); + return "a bean of type '" + type.getName() + "'"; } return "a bean named '" + cause.getBeanName() + "'"; } + private Class extractBeanType(ResolvableType resolvableType) { + ResolvableType collectionType = resolvableType.asCollection(); + if (!collectionType.equals(ResolvableType.NONE)) { + return collectionType.getGeneric(0).getRawClass(); + } + ResolvableType mapType = resolvableType.asMap(); + if (!mapType.equals(ResolvableType.NONE)) { + return mapType.getGeneric(1).getRawClass(); + } + return resolvableType.getRawClass(); + } + private List getAutoConfigurationResults( NoSuchBeanDefinitionException cause) { List results = new ArrayList(); @@ -203,9 +217,9 @@ class NoSuchBeanDefinitionFailureAnalyzer return false; } String name = cause.getBeanName(); - Class type = cause.getBeanType(); + ResolvableType resolvableType = cause.getResolvableType(); return ((name != null && hasName(candidate, name)) - || (type != null && hasType(candidate, type))); + || (resolvableType != null && hasType(candidate, extractBeanType(resolvableType)))); } private boolean hasName(MethodMetadata methodMetadata, String name) { diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/diagnostics/analyzer/NoSuchBeanDefinitionFailureAnalyzerTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/diagnostics/analyzer/NoSuchBeanDefinitionFailureAnalyzerTests.java index 5e988e62594..3d04f8b9f90 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/diagnostics/analyzer/NoSuchBeanDefinitionFailureAnalyzerTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/diagnostics/analyzer/NoSuchBeanDefinitionFailureAnalyzerTests.java @@ -17,7 +17,9 @@ package org.springframework.boot.autoconfigure.diagnostics.analyzer; import java.util.ArrayList; +import java.util.Collection; import java.util.List; +import java.util.Map; import org.junit.Test; @@ -81,6 +83,30 @@ public class NoSuchBeanDefinitionFailureAnalyzerTests { assertActionMissingType(analysis, String.class); } + @Test + public void failureAnalysisForMissingCollectionType() throws Exception { + FailureAnalysis analysis = analyzeFailure( + createFailure(StringCollectionConfiguration.class)); + assertDescriptionConstructorMissingType(analysis, StringCollectionHandler.class, 0, + String.class); + assertBeanMethodDisabled(analysis, + "did not find property 'spring.string.enabled'", + TestPropertyAutoConfiguration.class, "string"); + assertActionMissingType(analysis, String.class); + } + + @Test + public void failureAnalysisForMissingMapType() throws Exception { + FailureAnalysis analysis = analyzeFailure( + createFailure(StringMapConfiguration.class)); + assertDescriptionConstructorMissingType(analysis, StringMapHandler.class, 0, + String.class); + assertBeanMethodDisabled(analysis, + "did not find property 'spring.string.enabled'", + TestPropertyAutoConfiguration.class, "string"); + assertActionMissingType(analysis, String.class); + } + @Test public void failureAnalysisForMissingPropertySubType() { FailureAnalysis analysis = analyzeFailure( @@ -239,6 +265,20 @@ public class NoSuchBeanDefinitionFailureAnalyzerTests { } + @Configuration + @ImportAutoConfiguration(TestPropertyAutoConfiguration.class) + @Import(StringCollectionHandler.class) + protected static class StringCollectionConfiguration { + + } + + @Configuration + @ImportAutoConfiguration(TestPropertyAutoConfiguration.class) + @Import(StringMapHandler.class) + protected static class StringMapConfiguration { + + } + @Configuration @ImportAutoConfiguration(TestPropertyAutoConfiguration.class) @Import(NumberHandler.class) @@ -329,4 +369,18 @@ public class NoSuchBeanDefinitionFailureAnalyzerTests { } + protected static class StringCollectionHandler { + + public StringCollectionHandler(Collection collection) { + } + + } + + protected static class StringMapHandler { + + public StringMapHandler(Map map) { + } + + } + }