Merge branch '6.2.x'

This commit is contained in:
Sam Brannen 2025-02-10 11:49:50 +01:00
commit e6f2f86f9f
5 changed files with 53 additions and 21 deletions

View File

@ -60,6 +60,7 @@ import org.springframework.util.Assert;
* @author Simon Baslé * @author Simon Baslé
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Sam Brannen * @author Sam Brannen
* @author Yanming Zhou
* @since 6.2 * @since 6.2
*/ */
class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor, Ordered { class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor, Ordered {
@ -169,8 +170,10 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor,
} }
else if (requireExistingBean) { else if (requireExistingBean) {
Field field = handler.getField(); Field field = handler.getField();
throw new IllegalStateException( throw new IllegalStateException("""
"Unable to replace bean: there is no bean with name '%s' and type %s%s." Unable to replace bean: there is no bean with name '%s' and type %s%s. \
If the bean is defined in a @Bean method, make sure the return type is the \
most specific type possible (for example, the concrete implementation type)."""
.formatted(beanName, handler.getBeanType(), requiredByField(field))); .formatted(beanName, handler.getBeanType(), requiredByField(field)));
} }
// 4) We are creating a bean by-name with the provided beanName. // 4) We are creating a bean by-name with the provided beanName.
@ -258,7 +261,11 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor,
String message = "Unable to select a bean to wrap: "; String message = "Unable to select a bean to wrap: ";
int candidateCount = candidateNames.size(); int candidateCount = candidateNames.size();
if (candidateCount == 0) { if (candidateCount == 0) {
message += "there are no beans of type %s%s.".formatted(beanType, requiredByField(field)); message += """
there are no beans of type %s%s. \
If the bean is defined in a @Bean method, make sure the return type is the \
most specific type possible (for example, the concrete implementation type)."""
.formatted(beanType, requiredByField(field));
} }
else { else {
message += "found %d beans of type %s%s: %s" message += "found %d beans of type %s%s: %s"
@ -272,8 +279,10 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor,
// We are wrapping an existing bean by-name. // We are wrapping an existing bean by-name.
Set<String> candidates = getExistingBeanNamesByType(beanFactory, handler, false); Set<String> candidates = getExistingBeanNamesByType(beanFactory, handler, false);
if (!candidates.contains(beanName)) { if (!candidates.contains(beanName)) {
throw new IllegalStateException( throw new IllegalStateException("""
"Unable to wrap bean: there is no bean with name '%s' and type %s%s." Unable to wrap bean: there is no bean with name '%s' and type %s%s. \
If the bean is defined in a @Bean method, make sure the return type is the \
most specific type possible (for example, the concrete implementation type)."""
.formatted(beanName, beanType, requiredByField(field))); .formatted(beanName, beanType, requiredByField(field)));
} }
} }
@ -297,8 +306,10 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor,
int candidateCount = candidateNames.size(); int candidateCount = candidateNames.size();
if (candidateCount == 0) { if (candidateCount == 0) {
if (requireExistingBean) { if (requireExistingBean) {
throw new IllegalStateException( throw new IllegalStateException("""
"Unable to override bean: there are no beans of type %s%s." Unable to override bean: there are no beans of type %s%s. \
If the bean is defined in a @Bean method, make sure the return type is the \
most specific type possible (for example, the concrete implementation type)."""
.formatted(beanType, requiredByField(field))); .formatted(beanType, requiredByField(field)));
} }
return null; return null;

View File

@ -87,7 +87,9 @@ class BeanOverrideBeanFactoryPostProcessorTests {
.isThrownBy(context::refresh) .isThrownBy(context::refresh)
.withMessage(""" .withMessage("""
Unable to replace bean: there is no bean with name 'descriptionBean' \ Unable to replace bean: there is no bean with name 'descriptionBean' \
and type java.lang.String (as required by field 'ByNameTestCase.description')."""); and type java.lang.String (as required by field 'ByNameTestCase.description'). \
If the bean is defined in a @Bean method, make sure the return type is the most \
specific type possible (for example, the concrete implementation type).""");
} }
@Test @Test
@ -99,7 +101,9 @@ class BeanOverrideBeanFactoryPostProcessorTests {
.isThrownBy(context::refresh) .isThrownBy(context::refresh)
.withMessage(""" .withMessage("""
Unable to replace bean: there is no bean with name 'descriptionBean' \ Unable to replace bean: there is no bean with name 'descriptionBean' \
and type java.lang.String (as required by field 'ByNameTestCase.description')."""); and type java.lang.String (as required by field 'ByNameTestCase.description'). \
If the bean is defined in a @Bean method, make sure the return type is the most \
specific type possible (for example, the concrete implementation type).""");
} }
@Test @Test
@ -146,7 +150,9 @@ class BeanOverrideBeanFactoryPostProcessorTests {
.isThrownBy(context::refresh) .isThrownBy(context::refresh)
.withMessage(""" .withMessage("""
Unable to override bean: there are no beans of type java.lang.Integer \ Unable to override bean: there are no beans of type java.lang.Integer \
(as required by field 'ByTypeTestCase.counter')."""); (as required by field 'ByTypeTestCase.counter'). \
If the bean is defined in a @Bean method, make sure the return type is the most \
specific type possible (for example, the concrete implementation type).""");
} }
@Test @Test

View File

@ -42,7 +42,9 @@ public class TestBeanTests {
.isThrownBy(context::refresh) .isThrownBy(context::refresh)
.withMessage(""" .withMessage("""
Unable to replace bean: there is no bean with name 'beanToOverride' \ Unable to replace bean: there is no bean with name 'beanToOverride' \
and type java.lang.String (as required by field 'FailureByNameLookup.example')."""); and type java.lang.String (as required by field 'FailureByNameLookup.example'). \
If the bean is defined in a @Bean method, make sure the return type is the most \
specific type possible (for example, the concrete implementation type).""");
} }
@Test @Test
@ -54,7 +56,9 @@ public class TestBeanTests {
.isThrownBy(context::refresh) .isThrownBy(context::refresh)
.withMessage(""" .withMessage("""
Unable to replace bean: there is no bean with name 'beanToOverride' \ Unable to replace bean: there is no bean with name 'beanToOverride' \
and type java.lang.String (as required by field 'FailureByNameLookup.example')."""); and type java.lang.String (as required by field 'FailureByNameLookup.example'). \
If the bean is defined in a @Bean method, make sure the return type is the most \
specific type possible (for example, the concrete implementation type).""");
} }
@Test @Test
@ -64,8 +68,9 @@ public class TestBeanTests {
assertThatIllegalStateException() assertThatIllegalStateException()
.isThrownBy(context::refresh) .isThrownBy(context::refresh)
.withMessage(""" .withMessage("""
Unable to override bean: there are no beans of \ Unable to override bean: there are no beans of type %s (as required by field '%s.example'). \
type %s (as required by field '%s.example').""", If the bean is defined in a @Bean method, make sure the return type is the most \
specific type possible (for example, the concrete implementation type).""",
String.class.getName(), FailureByTypeLookup.class.getSimpleName()); String.class.getName(), FailureByTypeLookup.class.getSimpleName());
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2024 the original author or authors. * Copyright 2002-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -42,7 +42,9 @@ class MockitoBeanConfigurationErrorTests {
.isThrownBy(context::refresh) .isThrownBy(context::refresh)
.withMessage(""" .withMessage("""
Unable to replace bean: there is no bean with name 'beanToOverride' \ Unable to replace bean: there is no bean with name 'beanToOverride' \
and type java.lang.String (as required by field 'FailureByNameLookup.example')."""); and type java.lang.String (as required by field 'FailureByNameLookup.example'). \
If the bean is defined in a @Bean method, make sure the return type is the most \
specific type possible (for example, the concrete implementation type).""");
} }
@Test @Test
@ -54,7 +56,9 @@ class MockitoBeanConfigurationErrorTests {
.isThrownBy(context::refresh) .isThrownBy(context::refresh)
.withMessage(""" .withMessage("""
Unable to replace bean: there is no bean with name 'beanToOverride' \ Unable to replace bean: there is no bean with name 'beanToOverride' \
and type java.lang.String (as required by field 'FailureByNameLookup.example')."""); and type java.lang.String (as required by field 'FailureByNameLookup.example'). \
If the bean is defined in a @Bean method, make sure the return type is the most \
specific type possible (for example, the concrete implementation type).""");
} }
@Test @Test
@ -65,7 +69,9 @@ class MockitoBeanConfigurationErrorTests {
.isThrownBy(context::refresh) .isThrownBy(context::refresh)
.withMessage(""" .withMessage("""
Unable to override bean: there are no beans of \ Unable to override bean: there are no beans of \
type java.lang.String (as required by field 'FailureByTypeLookup.example')."""); type java.lang.String (as required by field 'FailureByTypeLookup.example'). \
If the bean is defined in a @Bean method, make sure the return type is the most \
specific type possible (for example, the concrete implementation type).""");
} }
@Test @Test

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2024 the original author or authors. * Copyright 2002-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -41,7 +41,9 @@ class MockitoSpyBeanConfigurationErrorTests {
.isThrownBy(context::refresh) .isThrownBy(context::refresh)
.withMessage(""" .withMessage("""
Unable to wrap bean: there is no bean with name 'beanToSpy' and \ Unable to wrap bean: there is no bean with name 'beanToSpy' and \
type java.lang.String (as required by field 'ByNameSingleLookup.example')."""); type java.lang.String (as required by field 'ByNameSingleLookup.example'). \
If the bean is defined in a @Bean method, make sure the return type is the most \
specific type possible (for example, the concrete implementation type).""");
} }
@Test @Test
@ -52,7 +54,9 @@ class MockitoSpyBeanConfigurationErrorTests {
.isThrownBy(context::refresh) .isThrownBy(context::refresh)
.withMessage(""" .withMessage("""
Unable to select a bean to wrap: there are no beans of type java.lang.String \ Unable to select a bean to wrap: there are no beans of type java.lang.String \
(as required by field 'ByTypeSingleLookup.example')."""); (as required by field 'ByTypeSingleLookup.example'). \
If the bean is defined in a @Bean method, make sure the return type is the most \
specific type possible (for example, the concrete implementation type).""");
} }
@Test @Test