mirror of
https://github.com/spring-projects/spring-framework
synced 2026-06-08 17:33:33 +00:00
Skip annotations that cannot be processed in AnnotationBeanNameGenerator
Prior to this commit, AnnotationBeanNameGenerator failed when searching for a convention-based bean name, if an annotation referenced a non-existent class. To address that, this commit introduces a try-catch block around each invocation of MergedAnnotation.asAnnotationAttributes() and skips processing of the current MergedAnnotation if an exception occurs, which is likely due to a type referenced from an annotation attribute not being present in the classpath. See gh-31203 Closes gh-36524
This commit is contained in:
+11
-1
@@ -139,7 +139,17 @@ public class AnnotationBeanNameGenerator implements BeanNameGenerator {
|
||||
Set<AnnotationAttributes> visited = new HashSet<>();
|
||||
|
||||
for (MergedAnnotation<Annotation> mergedAnnotation : mergedAnnotations) {
|
||||
AnnotationAttributes attributes = mergedAnnotation.asAnnotationAttributes(ADAPTATIONS);
|
||||
AnnotationAttributes attributes = null;
|
||||
try {
|
||||
attributes = mergedAnnotation.asAnnotationAttributes(ADAPTATIONS);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
// Ignore exception and current MergedAnnotation, assuming that values of the
|
||||
// MergedAnnotation could not be adapted to a Map/AnnotationAttributes due to
|
||||
// missing types referenced via annotation attributes.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (visited.add(attributes)) {
|
||||
String annotationType = mergedAnnotation.getType().getName();
|
||||
Set<String> metaAnnotationTypes = this.metaAnnotationTypesCache.computeIfAbsent(annotationType,
|
||||
|
||||
+54
@@ -31,7 +31,12 @@ import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefiniti
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.SimpleBeanDefinitionRegistry;
|
||||
import org.springframework.core.OverridingClassLoader;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.core.type.classreading.MetadataReader;
|
||||
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -91,6 +96,14 @@ class AnnotationBeanNameGeneratorTests {
|
||||
"myComponent", "myService");
|
||||
}
|
||||
|
||||
@Test // gh-gh-36524
|
||||
void generateBeanNameForConventionBasedComponentWithMissingAnnotationAttributeTypeViaAsm() throws Exception {
|
||||
FilteringClassLoader classLoader = new FilteringClassLoader(getClass().getClassLoader());
|
||||
MetadataReaderFactory readerFactory = new SimpleMetadataReaderFactory(classLoader);
|
||||
MetadataReader reader = readerFactory.getMetadataReader(ConventionBasedComponentWithMissingAnnotationAttributeType.class.getName());
|
||||
assertGeneratedName(reader.getAnnotationMetadata(), "myComponent");
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateBeanNameForComponentWithConflictingNames() {
|
||||
BeanDefinition bd = annotatedBeanDef(ComponentWithMultipleConflictingNames.class);
|
||||
@@ -171,6 +184,11 @@ class AnnotationBeanNameGeneratorTests {
|
||||
assertThat(generateBeanName(bd)).isNotBlank().isEqualTo(expectedName);
|
||||
}
|
||||
|
||||
private void assertGeneratedName(AnnotationMetadata annotationMetadata, String expectedName) {
|
||||
BeanDefinition bd = new AnnotatedGenericBeanDefinition(annotationMetadata);
|
||||
assertThat(generateBeanName(bd)).isNotBlank().isEqualTo(expectedName);
|
||||
}
|
||||
|
||||
private void assertGeneratedNameIsDefault(Class<?> clazz) {
|
||||
BeanDefinition bd = annotatedBeanDef(clazz);
|
||||
String expectedName = this.beanNameGenerator.buildDefaultBeanName(bd);
|
||||
@@ -230,6 +248,22 @@ class AnnotationBeanNameGeneratorTests {
|
||||
static class ConventionBasedComponentWithMultipleConflictingNames {
|
||||
}
|
||||
|
||||
static class FilteredType {
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface ExampleAnnotation {
|
||||
|
||||
Class<?> value() default Void.class;
|
||||
|
||||
String description() default "";
|
||||
}
|
||||
|
||||
@ExampleAnnotation(value = FilteredType.class, description = "optional")
|
||||
@ConventionBasedComponent1("myComponent")
|
||||
static class ConventionBasedComponentWithMissingAnnotationAttributeType {
|
||||
}
|
||||
|
||||
@Component
|
||||
private static class AnonymousComponent {
|
||||
}
|
||||
@@ -376,4 +410,24 @@ class AnnotationBeanNameGeneratorTests {
|
||||
static class StereotypeWithGeneratedName {
|
||||
}
|
||||
|
||||
static class FilteringClassLoader extends OverridingClassLoader {
|
||||
|
||||
FilteringClassLoader(ClassLoader parent) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEligibleForOverriding(String className) {
|
||||
return className.startsWith(AnnotationBeanNameGeneratorTests.class.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> loadClassForOverriding(String name) throws ClassNotFoundException {
|
||||
if (name.contains("Filtered")) {
|
||||
throw new ClassNotFoundException(name);
|
||||
}
|
||||
return super.loadClassForOverriding(name);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user