Deprecate convention-based @Component stereotype names in favor of @AliasFor
When use of the deprecated feature is detected, a WARNING log message will be generated analogous to the following. WARN o.s.c.a.AnnotationBeanNameGenerator - Support for convention-based stereotype names is deprecated and will be removed in a future version of the framework. Please annotate the 'value' attribute in @org.springframework.context.annotation.AnnotationBeanNameGeneratorTests$ConventionBasedComponent1 with @AliasFor(annotation=Component.class) to declare an explicit alias for @Component's 'value' attribute. See gh-31089 Closes gh-31093
This commit is contained in:
@@ -22,6 +22,9 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
@@ -77,6 +80,18 @@ public class AnnotationBeanNameGenerator implements BeanNameGenerator {
|
||||
|
||||
private static final String COMPONENT_ANNOTATION_CLASSNAME = "org.springframework.stereotype.Component";
|
||||
|
||||
/**
|
||||
* Set used to track which stereotype annotations have already been checked
|
||||
* to see if they use a convention-based override for the {@code value}
|
||||
* attribute in {@code @Component}.
|
||||
* @since 6.1
|
||||
* @see #determineBeanNameFromAnnotation(AnnotatedBeanDefinition)
|
||||
*/
|
||||
private static final Set<String> conventionBasedStereotypeCheckCache = ConcurrentHashMap.newKeySet();
|
||||
|
||||
|
||||
private final Log logger = LogFactory.getLog(AnnotationBeanNameGenerator.class);
|
||||
|
||||
private final Map<String, Set<String>> metaAnnotationTypesCache = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
@@ -117,6 +132,15 @@ public class AnnotationBeanNameGenerator implements BeanNameGenerator {
|
||||
if (isStereotypeWithNameValue(annotationType, metaAnnotationTypes, attributes)) {
|
||||
Object value = attributes.get("value");
|
||||
if (value instanceof String currentName && !currentName.isBlank()) {
|
||||
if (conventionBasedStereotypeCheckCache.add(annotationType) &&
|
||||
metaAnnotationTypes.contains(COMPONENT_ANNOTATION_CLASSNAME) && logger.isWarnEnabled()) {
|
||||
logger.warn("""
|
||||
Support for convention-based stereotype names is deprecated and will \
|
||||
be removed in a future version of the framework. Please annotate the \
|
||||
'value' attribute in @%s with @AliasFor(annotation=Component.class) \
|
||||
to declare an explicit alias for @Component's 'value' attribute."""
|
||||
.formatted(annotationType));
|
||||
}
|
||||
if (beanName != null && !currentName.equals(beanName)) {
|
||||
throw new IllegalStateException("Stereotype annotations suggest inconsistent " +
|
||||
"component names: '" + beanName + "' versus '" + currentName + "'");
|
||||
|
||||
@@ -23,19 +23,35 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Indicates that an annotated class is a "component".
|
||||
* Such classes are considered as candidates for auto-detection
|
||||
* Indicates that the annotated class is a <em>component</em>.
|
||||
*
|
||||
* <p>Such classes are considered as candidates for auto-detection
|
||||
* when using annotation-based configuration and classpath scanning.
|
||||
*
|
||||
* <p>A component may optionally specify a logical component name via the
|
||||
* {@link #value value} attribute of this annotation.
|
||||
*
|
||||
* <p>Other class-level annotations may be considered as identifying
|
||||
* a component as well, typically a special kind of component —
|
||||
* for example, the {@link Repository @Repository} annotation or AspectJ's
|
||||
* {@link org.aspectj.lang.annotation.Aspect @Aspect} annotation.
|
||||
* {@link org.aspectj.lang.annotation.Aspect @Aspect} annotation. Note, however,
|
||||
* that the {@code @Aspect} annotation does not automatically make a class
|
||||
* eligible for classpath scanning.
|
||||
*
|
||||
* <p>As of Spring Framework 6.1, custom component stereotype annotations should
|
||||
* use {@link org.springframework.core.annotation.AliasFor @AliasFor} to declare
|
||||
* an explicit alias for this annotation's {@link #value} attribute. See the
|
||||
* source code declaration of {@link Repository#value()} and
|
||||
* <p>Any annotation meta-annotated with {@code @Component} is considered a
|
||||
* <em>stereotype</em> annotation which makes the annotated class eligible for
|
||||
* classpath scanning. For example, {@link Service @Service},
|
||||
* {@link Controller @Controller}, and {@link Repository @Repository} are
|
||||
* stereotype annotations. Stereotype annotations may also support configuration
|
||||
* of a logical component name by overriding the {@link #value} attribute of this
|
||||
* annotation via {@link org.springframework.core.annotation.AliasFor @AliasFor}.
|
||||
*
|
||||
* <p>As of Spring Framework 6.1, support for configuring the name of a stereotype
|
||||
* component by convention (i.e., via a {@code String value()} attribute without
|
||||
* {@code @AliasFor}) is deprecated and will be removed in a future version of the
|
||||
* framework. Consequently, custom stereotype annotations must use {@code @AliasFor}
|
||||
* to declare an explicit alias for this annotation's {@link #value} attribute.
|
||||
* See the source code declaration of {@link Repository#value()} and
|
||||
* {@link org.springframework.web.bind.annotation.ControllerAdvice#name()
|
||||
* ControllerAdvice.name()} for concrete examples.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user