Reinstate support for @javax.annotation.ManagedBean & @javax.inject.Named

This commit reinstates support for the legacy JSR-250
@javax.annotation.ManagedBean and JSR-330 @javax.inject.Named
annotations with regard to component name lookups and component
scanning.

Closes gh-31090
This commit is contained in:
Sam Brannen
2023-08-22 13:47:21 +02:00
parent aaa0a2be63
commit e1826d2322
11 changed files with 175 additions and 22 deletions

View File

@@ -41,8 +41,10 @@ import org.springframework.util.StringUtils;
* themselves annotated with {@code @Component}.
*
* <p>Also supports Jakarta EE's {@link jakarta.annotation.ManagedBean} and
* JSR-330's {@link jakarta.inject.Named} annotations, if available. Note that
* Spring component annotations always override such standard annotations.
* JSR-330's {@link jakarta.inject.Named} annotations (as well as their pre-Jakarta
* {@code javax.annotation.ManagedBean} and {@code javax.inject.Named} equivalents),
* if available. Note that Spring component annotations always override such
* standard annotations.
*
* <p>If the annotation's value doesn't indicate a bean name, an appropriate
* name will be built based on the short name of the class (with the first
@@ -53,6 +55,7 @@ import org.springframework.util.StringUtils;
*
* @author Juergen Hoeller
* @author Mark Fisher
* @author Sam Brannen
* @since 2.5
* @see org.springframework.stereotype.Component#value()
* @see org.springframework.stereotype.Repository#value()
@@ -134,7 +137,9 @@ public class AnnotationBeanNameGenerator implements BeanNameGenerator {
boolean isStereotype = annotationType.equals(COMPONENT_ANNOTATION_CLASSNAME) ||
metaAnnotationTypes.contains(COMPONENT_ANNOTATION_CLASSNAME) ||
annotationType.equals("jakarta.annotation.ManagedBean") ||
annotationType.equals("jakarta.inject.Named");
annotationType.equals("javax.annotation.ManagedBean") ||
annotationType.equals("jakarta.inject.Named") ||
annotationType.equals("javax.inject.Named");
return (isStereotype && attributes != null && attributes.containsKey("value"));
}

View File

@@ -62,11 +62,13 @@ import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* A component provider that provides candidate components from a base package. Can
* use {@link CandidateComponentsIndex the index} if it is available of scans the
* classpath otherwise. Candidate components are identified by applying exclude and
* include filters. {@link AnnotationTypeFilter}, {@link AssignableTypeFilter} include
* filters on an annotation/superclass that are annotated with {@link Indexed} are
* A component provider that scans for candidate components starting from a
* specified base package. Can use the {@linkplain CandidateComponentsIndex component
* index}, if it is available, and scans the classpath otherwise.
*
* <p>Candidate components are identified by applying exclude and include filters.
* {@link AnnotationTypeFilter} and {@link AssignableTypeFilter} include filters
* for an annotation/target-type that is annotated with {@link Indexed} are
* supported: if any other include filter is specified, the index is ignored and
* classpath scanning is used instead.
*
@@ -201,8 +203,9 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
* {@link Repository @Repository}, {@link Service @Service}, and
* {@link Controller @Controller} stereotype annotations.
* <p>Also supports Jakarta EE's {@link jakarta.annotation.ManagedBean} and
* JSR-330's {@link jakarta.inject.Named} annotations, if available.
*
* JSR-330's {@link jakarta.inject.Named} annotations (as well as their
* pre-Jakarta {@code javax.annotation.ManagedBean} and {@code javax.inject.Named}
* equivalents), if available.
*/
@SuppressWarnings("unchecked")
protected void registerDefaultFilters() {
@@ -216,11 +219,27 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
catch (ClassNotFoundException ex) {
// JSR-250 1.1 API (as included in Jakarta EE) not available - simply skip.
}
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
}
catch (ClassNotFoundException ex) {
// JSR-250 1.1 API not available - simply skip.
}
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("jakarta.inject.Named", cl)), false));
logger.trace("JSR-330 'jakarta.inject.Named' annotation found and supported for component scanning");
}
catch (ClassNotFoundException ex) {
// JSR-330 API (as included in Jakarta EE) not available - simply skip.
}
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
@@ -306,7 +325,7 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
/**
* Scan the class path for candidate components.
* Scan the component index or class path for candidate components.
* @param basePackage the package to check for annotated classes
* @return a corresponding Set of autodetected bean definitions
*/
@@ -320,7 +339,7 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
}
/**
* Determine if the index can be used by this instance.
* Determine if the component index can be used by this instance.
* @return {@code true} if the index is available and the configuration of this
* instance is supported by it, {@code false} otherwise
* @since 5.0
@@ -345,7 +364,8 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
if (filter instanceof AnnotationTypeFilter annotationTypeFilter) {
Class<? extends Annotation> annotationType = annotationTypeFilter.getAnnotationType();
return (AnnotationUtils.isAnnotationDeclaredLocally(Indexed.class, annotationType) ||
annotationType.getName().startsWith("jakarta."));
annotationType.getName().startsWith("jakarta.") ||
annotationType.getName().startsWith("javax."));
}
if (filter instanceof AssignableTypeFilter assignableTypeFilter) {
Class<?> target = assignableTypeFilter.getTargetType();