Improve exception handling in bean override support

- Do not silently abort bean override processing if the ApplicationContext
  is not a BeanDefinitionRegistry.

- Include conflicting bean names in error messages instead of just the
  number of conflicting beans.

- Consistently throw IllegalStateException.

- etc.
This commit is contained in:
Sam Brannen
2024-06-03 16:57:19 +02:00
parent 7a11899c0c
commit acdd8a0015
7 changed files with 48 additions and 39 deletions

View File

@@ -130,15 +130,16 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor,
String beanName = overrideMetadata.getBeanName();
BeanDefinition existingBeanDefinition = null;
if (beanName == null) {
Set<String> candidates = getExistingBeanNamesByType(beanFactory, overrideMetadata, true);
if (candidates.size() != 1) {
Field f = overrideMetadata.getField();
throw new IllegalStateException("Unable to select a bean definition to override: " +
candidates.size() + " bean definitions found of type " + overrideMetadata.getBeanType() +
" (as required by annotated field '" + f.getDeclaringClass().getSimpleName() +
"." + f.getName() + "')");
Set<String> candidateNames = getExistingBeanNamesByType(beanFactory, overrideMetadata, true);
int candidateCount = candidateNames.size();
if (candidateCount != 1) {
Field field = overrideMetadata.getField();
throw new IllegalStateException("Unable to select a bean definition to override: found " +
candidateCount + " bean definitions of type " + overrideMetadata.getBeanType() +
" (as required by annotated field '" + field.getDeclaringClass().getSimpleName() +
"." + field.getName() + "')" + (candidateCount > 0 ? ": " + candidateNames : ""));
}
beanName = candidates.iterator().next();
beanName = candidateNames.iterator().next();
existingBeanDefinition = beanFactory.getBeanDefinition(beanName);
}
else {
@@ -147,8 +148,8 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor,
existingBeanDefinition = beanFactory.getBeanDefinition(beanName);
}
else if (enforceExistingDefinition) {
throw new IllegalStateException("Unable to override bean '" + beanName + "': there is no" +
" bean definition to replace with that name of type " + overrideMetadata.getBeanType());
throw new IllegalStateException("Unable to override bean '" + beanName + "': there is no " +
"bean definition to replace with that name of type " + overrideMetadata.getBeanType());
}
}
@@ -181,20 +182,21 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor,
String beanName = metadata.getBeanName();
if (beanName == null) {
Set<String> candidateNames = getExistingBeanNamesByType(beanFactory, metadata, true);
if (candidateNames.size() != 1) {
Field f = metadata.getField();
throw new IllegalStateException("Unable to select a bean to override by wrapping: " +
candidateNames.size() + " bean instances found of type " + metadata.getBeanType() +
" (as required by annotated field '" + f.getDeclaringClass().getSimpleName() +
"." + f.getName() + "')");
int candidateCount = candidateNames.size();
if (candidateCount != 1) {
Field field = metadata.getField();
throw new IllegalStateException("Unable to select a bean to override by wrapping: found " +
candidateCount + " bean instances of type " + metadata.getBeanType() +
" (as required by annotated field '" + field.getDeclaringClass().getSimpleName() +
"." + field.getName() + "')" + (candidateCount > 0 ? ": " + candidateNames : ""));
}
beanName = candidateNames.iterator().next();
}
else {
Set<String> candidates = getExistingBeanNamesByType(beanFactory, metadata, false);
if (!candidates.contains(beanName)) {
throw new IllegalStateException("Unable to override bean '" + beanName + "' by wrapping: there is no" +
" existing bean instance with that name of type " + metadata.getBeanType());
throw new IllegalStateException("Unable to override bean '" + beanName + "' by wrapping: there is no " +
"existing bean instance with that name of type " + metadata.getBeanType());
}
}
this.overrideRegistrar.markWrapEarly(metadata, beanName);

View File

@@ -81,9 +81,11 @@ class BeanOverrideContextCustomizer implements ContextCustomizer {
@Override
public void customizeContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) {
if (context instanceof BeanDefinitionRegistry registry) {
registerInfrastructure(registry, this.detectedClasses);
if (!(context instanceof BeanDefinitionRegistry registry)) {
throw new IllegalStateException("Cannot process bean overrides with an ApplicationContext " +
"that doesn't implement BeanDefinitionRegistry: " + context.getClass());
}
registerInfrastructure(registry, this.detectedClasses);
}
@Override

View File

@@ -111,9 +111,8 @@ class TestBeanOverrideProcessor implements BeanOverrideProcessor {
@Override
public TestBeanOverrideMetadata createMetadata(Annotation overrideAnnotation, Class<?> testClass, Field field) {
if (!(overrideAnnotation instanceof TestBean testBeanAnnotation)) {
throw new IllegalStateException(String.format("Invalid annotation passed to %s: expected @TestBean on field %s.%s",
TestBeanOverrideProcessor.class.getSimpleName(), field.getDeclaringClass().getName(),
field.getName()));
throw new IllegalStateException("Invalid annotation passed to %s: expected @TestBean on field %s.%s"
.formatted(getClass().getSimpleName(), field.getDeclaringClass().getName(), field.getName()));
}
Method overrideMethod;
String methodName = testBeanAnnotation.methodName();
@@ -172,7 +171,7 @@ class TestBeanOverrideProcessor implements BeanOverrideProcessor {
return this.overrideMethod.invoke(null);
}
catch (IllegalAccessException | InvocationTargetException ex) {
throw new IllegalArgumentException("Could not invoke bean overriding method " + this.overrideMethod.getName() +
throw new IllegalStateException("Failed to invoke bean overriding method " + this.overrideMethod.getName() +
"; a static method with no formal parameters is expected", ex);
}
}