From bfeeb6dc4e1d7f62c4ab2864b6223bdb700d3cd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Fri, 2 Aug 2024 16:52:03 +0200 Subject: [PATCH] Relax requirements for NoUniqueBeanDefinitionFailureAnalyzer This commit relaxes the requirements for a non-null description to handle a NoUniqueBeanDefinitionException. This can happen if the exception has been thrown programmatically and no injection point is available. This allows the programmatic exception thrown when multiple cache managers are found to be handled properly. Closes gh-13348 --- ...NoUniqueBeanDefinitionFailureAnalyzer.java | 8 +++----- ...queBeanDefinitionFailureAnalyzerTests.java | 20 +++++++++++++++++-- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/NoUniqueBeanDefinitionFailureAnalyzer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/NoUniqueBeanDefinitionFailureAnalyzer.java index dee8f8eb9fd..26ec867e10a 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/NoUniqueBeanDefinitionFailureAnalyzer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/NoUniqueBeanDefinitionFailureAnalyzer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -44,15 +44,13 @@ class NoUniqueBeanDefinitionFailureAnalyzer extends AbstractInjectionFailureAnal @Override protected FailureAnalysis analyze(Throwable rootFailure, NoUniqueBeanDefinitionException cause, String description) { - if (description == null) { - return null; - } String[] beanNames = extractBeanNames(cause); if (beanNames == null) { return null; } StringBuilder message = new StringBuilder(); - message.append(String.format("%s required a single bean, but %d were found:%n", description, beanNames.length)); + message.append(String.format("%s required a single bean, but %d were found:%n", + (description != null) ? description : "A component", beanNames.length)); for (String beanName : beanNames) { buildMessage(message, beanName); } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/NoUniqueBeanDefinitionFailureAnalyzerTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/NoUniqueBeanDefinitionFailureAnalyzerTests.java index e8600faabe2..e67fc524062 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/NoUniqueBeanDefinitionFailureAnalyzerTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/NoUniqueBeanDefinitionFailureAnalyzerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ package org.springframework.boot.diagnostics.analyzer; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.NoUniqueBeanDefinitionException; import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.diagnostics.FailureAnalysis; @@ -101,6 +102,21 @@ class NoUniqueBeanDefinitionFailureAnalyzerTests { assertFoundBeans(failureAnalysis); } + @Test + void failureAnalysisWithoutInjectionPoints() { + this.context.registerBean("beanOne", TestBean.class); + this.context.register(DuplicateBeansProducer.class); + this.context.refresh(); + FailureAnalysis failureAnalysis = analyzeFailure(new NoUniqueBeanDefinitionException(TestBean.class, 3, + "no TestBeanProvider specified and expected single matching TestBean but found 3: beanOne,beanTwo,xmlBean")); + assertThat(failureAnalysis.getDescription()) + .startsWith("A component required a single bean, but 3 were found:"); + assertThat(failureAnalysis.getDescription()).contains("beanOne: defined in unknown location"); + assertThat(failureAnalysis.getDescription()) + .contains("beanTwo: defined by method 'beanTwo' in " + DuplicateBeansProducer.class.getName()); + assertThat(failureAnalysis.getDescription()).contains("xmlBean: a programmatically registered singleton"); + } + private BeanCreationException createFailure(Class consumer) { this.context.registerBean("beanOne", TestBean.class); this.context.register(DuplicateBeansProducer.class, consumer); @@ -114,7 +130,7 @@ class NoUniqueBeanDefinitionFailureAnalyzerTests { return null; } - private FailureAnalysis analyzeFailure(BeanCreationException failure) { + private FailureAnalysis analyzeFailure(Exception failure) { return this.analyzer.analyze(failure); }