Home / Class/ NoSuchBeanDefinitionFailureAnalyzerTests Class — spring-boot Architecture

NoSuchBeanDefinitionFailureAnalyzerTests Class — spring-boot Architecture

Architecture documentation for the NoSuchBeanDefinitionFailureAnalyzerTests class in NoSuchBeanDefinitionFailureAnalyzerTests.java from the spring-boot codebase.

Entity Profile

Relationship Graph

Source Code

core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/diagnostics/analyzer/NoSuchBeanDefinitionFailureAnalyzerTests.java lines 52–377

class NoSuchBeanDefinitionFailureAnalyzerTests {

	private final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

	private final NoSuchBeanDefinitionFailureAnalyzer analyzer = new NoSuchBeanDefinitionFailureAnalyzer(
			this.context.getBeanFactory());

	@Test
	void failureAnalysisForMultipleBeans() {
		FailureAnalysis analysis = analyzeFailure(new NoUniqueBeanDefinitionException(String.class, 2, "Test"));
		assertThat(analysis).isNull();
	}

	@Test
	void failureAnalysisForNoMatchType() {
		FailureAnalysis analysis = analyzeFailure(createFailure(StringHandler.class));
		assertThat(analysis).isNotNull();
		assertDescriptionConstructorMissingType(analysis, StringHandler.class, 0, String.class);
		assertThat(analysis.getDescription())
			.doesNotContain("No matching auto-configuration has been found for this type.");
		assertThat(analysis.getAction()).startsWith(
				String.format("Consider defining a bean of type '%s' in your configuration.", String.class.getName()));
	}

	@Test
	void failureAnalysisForMissingPropertyExactType() {
		FailureAnalysis analysis = analyzeFailure(createFailure(StringPropertyTypeConfiguration.class));
		assertThat(analysis).isNotNull();
		assertDescriptionConstructorMissingType(analysis, StringHandler.class, 0, String.class);
		assertBeanMethodDisabled(analysis, "did not find property 'spring.string.enabled'",
				TestPropertyAutoConfiguration.class, "string");
		assertActionMissingType(analysis, String.class);
	}

	@Test
	void failureAnalysisForMissingPropertySubType() {
		FailureAnalysis analysis = analyzeFailure(createFailure(IntegerPropertyTypeConfiguration.class));
		assertThat(analysis).isNotNull();
		assertDescriptionConstructorMissingType(analysis, NumberHandler.class, 0, Number.class);
		assertBeanMethodDisabled(analysis, "did not find property 'spring.integer.enabled'",
				TestPropertyAutoConfiguration.class, "integer");
		assertActionMissingType(analysis, Number.class);
	}

	@Test
	void failureAnalysisForMissingClassOnAutoConfigurationType() {
		FailureAnalysis analysis = analyzeFailure(createFailure(MissingClassOnAutoConfigurationConfiguration.class));
		assertThat(analysis).isNotNull();
		assertDescriptionConstructorMissingType(analysis, StringHandler.class, 0, String.class);
		assertClassDisabled(analysis, "did not find required class 'com.example.FooBar'", "string",
				ClassUtils.getShortName(TestTypeClassAutoConfiguration.class));
		assertActionMissingType(analysis, String.class);
	}

	@Test
	void failureAnalysisForExcludedAutoConfigurationType() {
		FatalBeanException failure = createFailure(StringHandler.class);
		addExclusions(this.analyzer, TestPropertyAutoConfiguration.class);
		FailureAnalysis analysis = analyzeFailure(failure);
		assertThat(analysis).isNotNull();
		assertDescriptionConstructorMissingType(analysis, StringHandler.class, 0, String.class);
		String configClass = ClassUtils.getShortName(TestPropertyAutoConfiguration.class.getName());
		assertClassDisabled(analysis, String.format("auto-configuration '%s' was excluded", configClass), "string",
				ClassUtils.getShortName(TestPropertyAutoConfiguration.class));
		assertActionMissingType(analysis, String.class);
	}

	@Test
	void failureAnalysisForSeveralConditionsType() {
		FailureAnalysis analysis = analyzeFailure(createFailure(SeveralAutoConfigurationTypeConfiguration.class));
		assertThat(analysis).isNotNull();
		assertDescriptionConstructorMissingType(analysis, StringHandler.class, 0, String.class);
		assertBeanMethodDisabled(analysis, "did not find property 'spring.string.enabled'",
				TestPropertyAutoConfiguration.class, "string");
		assertClassDisabled(analysis, "did not find required class 'com.example.FooBar'", "string",
				ClassUtils.getShortName(TestPropertyAutoConfiguration.class));
		assertActionMissingType(analysis, String.class);
	}

	@Test
	void failureAnalysisForNoMatchName() {
		FailureAnalysis analysis = analyzeFailure(createFailure(StringNameHandler.class));
		assertThat(analysis).isNotNull();
		assertThat(analysis.getDescription())
			.startsWith(String.format("Constructor in %s required a bean named '%s' that could not be found",
					StringNameHandler.class.getName(), "test-string"));
		assertThat(analysis.getAction())
			.startsWith(String.format("Consider defining a bean named '%s' in your configuration.", "test-string"));
	}

	@Test
	void failureAnalysisForMissingBeanName() {
		FailureAnalysis analysis = analyzeFailure(createFailure(StringMissingBeanNameConfiguration.class));
		assertThat(analysis).isNotNull();
		assertThat(analysis.getDescription())
			.startsWith(String.format("Constructor in %s required a bean named '%s' that could not be found",
					StringNameHandler.class.getName(), "test-string"));
		assertBeanMethodDisabled(analysis,
				"@ConditionalOnBean (types: java.lang.Integer; SearchStrategy: all) did not find any beans",
				TestMissingBeanAutoConfiguration.class, "string");
		assertActionMissingName(analysis, "test-string");
	}

	@Test
	void failureAnalysisForNullBeanByType() {
		FailureAnalysis analysis = analyzeFailure(createFailure(StringNullBeanConfiguration.class));
		assertThat(analysis).isNotNull();
		assertDescriptionConstructorMissingType(analysis, StringHandler.class, 0, String.class);
		assertUserDefinedBean(analysis, "as the bean value is null", TestNullBeanConfiguration.class, "string");
		assertActionMissingType(analysis, String.class);
	}

	@Test
	void failureAnalysisForUnmatchedQualifier() {
		FailureAnalysis analysis = analyzeFailure(createFailure(QualifiedBeanConfiguration.class));
		assertThat(analysis).isNotNull();
		assertThat(analysis.getDescription())
			.containsPattern("@org.springframework.beans.factory.annotation.Qualifier\\(\"*alpha\"*\\)");
	}

	private void assertDescriptionConstructorMissingType(FailureAnalysis analysis, Class<?> component, int index,
			Class<?> type) {
		String expected = String.format(
				"Parameter %s of constructor in %s required a bean of type '%s' that could not be found.", index,
				component.getName(), type.getName());
		assertThat(analysis.getDescription()).startsWith(expected);
	}

	private void assertActionMissingType(FailureAnalysis analysis, Class<?> type) {
		assertThat(analysis.getAction()).startsWith(String.format(
				"Consider revisiting the entries above or defining a bean of type '%s' in your configuration.",
				type.getName()));
		assertThat(analysis.getAction()).doesNotContain("@ConstructorBinding");
	}

	private void assertActionMissingName(FailureAnalysis analysis, String name) {
		assertThat(analysis.getAction()).startsWith(String.format(
				"Consider revisiting the entries above or defining a bean named '%s' in your configuration.", name));
	}

	private void assertBeanMethodDisabled(FailureAnalysis analysis, String description, Class<?> target,
			String methodName) {
		String expected = String.format("Bean method '%s' in '%s' not loaded because", methodName,
				ClassUtils.getShortName(target));
		assertThat(analysis.getDescription()).contains(expected);
		assertThat(analysis.getDescription()).contains(description);
	}

	private void assertClassDisabled(FailureAnalysis analysis, String description, String methodName,
			String className) {
		String expected = String.format("Bean method '%s' in '%s' not loaded because", methodName, className);
		assertThat(analysis.getDescription()).contains(expected);
		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, Class<?>... classes) {
		ConditionEvaluationReport report = (ConditionEvaluationReport) ReflectionTestUtils.getField(analyzer, "report");
		assertThat(report).isNotNull();
		List<String> exclusions = new ArrayList<>(report.getExclusions());
		for (Class<?> c : classes) {
			exclusions.add(c.getName());
		}
		report.recordExclusions(exclusions);
	}

	private FatalBeanException createFailure(Class<?> config, String... environment) {
		try {
			TestPropertyValues.of(environment).applyTo(this.context);
			this.context.register(config);
			this.context.refresh();
			throw new IllegalStateException("This should not be reached");
		}
		catch (FatalBeanException ex) {
			return ex;
		}
	}

	private @Nullable FailureAnalysis analyzeFailure(Exception failure) {
		FailureAnalysis analysis = this.analyzer.analyze(failure);
		if (analysis != null) {
			new LoggingFailureAnalysisReporter().report(analysis);
		}
		return analysis;
	}

	@Configuration(proxyBeanMethods = false)
	@ImportAutoConfiguration(TestPropertyAutoConfiguration.class)
	@Import(StringHandler.class)
	static class StringPropertyTypeConfiguration {

	}

	@Configuration(proxyBeanMethods = false)
	@ImportAutoConfiguration(TestPropertyAutoConfiguration.class)
	@Import(NumberHandler.class)
	static class IntegerPropertyTypeConfiguration {

	}

	@Configuration(proxyBeanMethods = false)
	@ImportAutoConfiguration(TestTypeClassAutoConfiguration.class)
	@Import(StringHandler.class)
	static class MissingClassOnAutoConfigurationConfiguration {

	}

	@Configuration(proxyBeanMethods = false)
	@ImportAutoConfiguration({ TestPropertyAutoConfiguration.class, TestTypeClassAutoConfiguration.class })
	@Import(StringHandler.class)
	static class SeveralAutoConfigurationTypeConfiguration {

	}

	@Configuration(proxyBeanMethods = false)
	@ImportAutoConfiguration(TestMissingBeanAutoConfiguration.class)
	@Import(StringNameHandler.class)
	static class StringMissingBeanNameConfiguration {

	}

	@Configuration(proxyBeanMethods = false)
	@ImportAutoConfiguration(TestNullBeanConfiguration.class)
	@Import(StringHandler.class)
	static class StringNullBeanConfiguration {

	}

	@Configuration(proxyBeanMethods = false)
	static class TestPropertyAutoConfiguration {

		@ConditionalOnProperty("spring.string.enabled")
		@Bean
		String string() {
			return "Test";
		}

		@ConditionalOnProperty("spring.integer.enabled")
		@Bean
		Integer integer() {
			return 42;
		}

	}

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnClass(name = "com.example.FooBar")
	static class TestTypeClassAutoConfiguration {

		@Bean
		String string() {
			return "Test";
		}

	}

	@Configuration(proxyBeanMethods = false)
	static class TestMissingBeanAutoConfiguration {

		@ConditionalOnBean(Integer.class)
		@Bean(name = "test-string")
		String string() {
			return "Test";
		}

	}

	@Configuration(proxyBeanMethods = false)
	static class TestNullBeanConfiguration {

		@Bean
		@Nullable String string() {
			return null;
		}

	}

	@Configuration(proxyBeanMethods = false)
	static class QualifiedBeanConfiguration {

		@Bean
		String consumer(@Qualifier("alpha") Thing thing) {
			return "consumer";
		}

		@Bean
		Thing producer() {
			return new Thing();
		}

		class Thing {

		}

	}

	static class StringHandler {

		StringHandler(String foo) {
		}

	}

	static class NumberHandler {

		NumberHandler(Number foo) {
		}

	}

	static class StringNameHandler {

		StringNameHandler(BeanFactory beanFactory) {
			beanFactory.getBean("test-string");
		}

	}

}

Domain

Analyze Your Own Codebase

Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.

Try Supermodel Free