mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-10-05 06:29:03 +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
(cherry picked from commit 00fbd91cca)
This commit is contained in:
+11
-1
@@ -143,7 +143,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
@@ -34,7 +34,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;
|
||||
@@ -94,6 +99,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);
|
||||
@@ -193,6 +206,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);
|
||||
@@ -252,6 +270,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 {
|
||||
}
|
||||
@@ -398,4 +432,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