From 774583dfa7dba5c3440c4a1341809ab2f3a88780 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 21 Sep 2021 17:07:42 +0200 Subject: [PATCH] Retain support for legacy PostConstruct/PreDestroy/Inject variants Also removes JAX-WS support from CommonAnnotationBeanPostProcessor. Closes gh-27444 See gh-27422 --- build.gradle | 1 - .../AutowiredAnnotationBeanPostProcessor.java | 26 +++- ...nitDestroyAnnotationBeanPostProcessor.java | 8 +- spring-context/spring-context.gradle | 5 +- .../annotation/AnnotationConfigUtils.java | 48 ++++-- .../CommonAnnotationBeanPostProcessor.java | 147 ++---------------- .../ClassPathBeanDefinitionScannerTests.java | 40 ++--- 7 files changed, 92 insertions(+), 183 deletions(-) diff --git a/build.gradle b/build.gradle index 42f5225e9b9..ac8e4863252 100644 --- a/build.gradle +++ b/build.gradle @@ -230,7 +230,6 @@ configure(allprojects) { project -> dependency "jakarta.validation:jakarta.validation-api:3.0.0" dependency "jakarta.websocket:jakarta.websocket-api:2.0.0" dependency "jakarta.xml.bind:jakarta.xml.bind-api:3.0.1" - dependency "jakarta.xml.ws:jakarta.xml.ws-api:3.0.1" dependency "com.sun.activation:jakarta.activation:2.0.1" dependency "com.sun.mail:jakarta.mail:2.0.1" diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java index fdbf9353912..d5c753e7291 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java @@ -75,8 +75,10 @@ import org.springframework.util.StringUtils; * by default, Spring's {@link Autowired @Autowired} and {@link Value @Value} * annotations. * - *

Also supports JSR-330's {@link jakarta.inject.Inject @Inject} annotation, + *

Also supports the common {@link jakarta.inject.Inject @Inject} annotation, * if available, as a direct alternative to Spring's own {@code @Autowired}. + * Additionally, it retains support for the {@code javax.inject.Inject} variant + * dating back to the original JSR-330 specification (as known from Java EE 6-8). * *

Autowired Constructors

*

Only one constructor of any given bean class may declare this annotation with @@ -154,20 +156,30 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA /** * Create a new {@code AutowiredAnnotationBeanPostProcessor} for Spring's * standard {@link Autowired @Autowired} and {@link Value @Value} annotations. - *

Also supports JSR-330's {@link jakarta.inject.Inject @Inject} annotation, - * if available. + *

Also supports the common {@link jakarta.inject.Inject @Inject} annotation, + * if available, as well as the original {@code javax.inject.Inject} variant. */ @SuppressWarnings("unchecked") public AutowiredAnnotationBeanPostProcessor() { this.autowiredAnnotationTypes.add(Autowired.class); this.autowiredAnnotationTypes.add(Value.class); + try { this.autowiredAnnotationTypes.add((Class) ClassUtils.forName("jakarta.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader())); - logger.trace("JSR-330 'jakarta.inject.Inject' annotation found and supported for autowiring"); + logger.trace("'jakarta.inject.Inject' annotation found and supported for autowiring"); + } + catch (ClassNotFoundException ex) { + // jakarta.inject API not available - simply skip. + } + + try { + this.autowiredAnnotationTypes.add((Class) + ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader())); + logger.trace("'javax.inject.Inject' annotation found and supported for autowiring"); } catch (ClassNotFoundException ex) { - // JSR-330 API not available - simply skip. + // javax.inject API not available - simply skip. } } @@ -177,7 +189,7 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA * setter methods, and arbitrary config methods. *

The default autowired annotation types are the Spring-provided * {@link Autowired @Autowired} and {@link Value @Value} annotations as well - * as JSR-330's {@link jakarta.inject.Inject @Inject} annotation, if available. + * as the common {@code @Inject} annotation, if available. *

This setter property exists so that developers can provide their own * (non-Spring-specific) annotation type to indicate that a member is supposed * to be autowired. @@ -193,7 +205,7 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA * setter methods, and arbitrary config methods. *

The default autowired annotation types are the Spring-provided * {@link Autowired @Autowired} and {@link Value @Value} annotations as well - * as JSR-330's {@link jakarta.inject.Inject @Inject} annotation, if available. + * as the common {@code @Inject} annotation, if available. *

This setter property exists so that developers can provide their own * (non-Spring-specific) annotation types to indicate that a member is supposed * to be autowired. diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/InitDestroyAnnotationBeanPostProcessor.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/InitDestroyAnnotationBeanPostProcessor.java index 6316848a5a7..2f1bd7763b2 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/InitDestroyAnnotationBeanPostProcessor.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/InitDestroyAnnotationBeanPostProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -66,7 +66,7 @@ import org.springframework.util.ReflectionUtils; * init method and destroy method, respectively. * *

Spring's {@link org.springframework.context.annotation.CommonAnnotationBeanPostProcessor} - * supports the JSR-250 {@link jakarta.annotation.PostConstruct} and {@link jakarta.annotation.PreDestroy} + * supports the {@link jakarta.annotation.PostConstruct} and {@link jakarta.annotation.PreDestroy} * annotations out of the box, as init annotation and destroy annotation, respectively. * Furthermore, it also supports the {@link jakarta.annotation.Resource} annotation * for annotation-driven injection of named beans. @@ -117,7 +117,7 @@ public class InitDestroyAnnotationBeanPostProcessor * methods to call after configuration of a bean. *

Any custom annotation can be used, since there are no required * annotation attributes. There is no default, although a typical choice - * is the JSR-250 {@link jakarta.annotation.PostConstruct} annotation. + * is the {@link jakarta.annotation.PostConstruct} annotation. */ public void setInitAnnotationType(Class initAnnotationType) { this.initAnnotationType = initAnnotationType; @@ -128,7 +128,7 @@ public class InitDestroyAnnotationBeanPostProcessor * methods to call when the context is shutting down. *

Any custom annotation can be used, since there are no required * annotation attributes. There is no default, although a typical choice - * is the JSR-250 {@link jakarta.annotation.PreDestroy} annotation. + * is the {@link jakarta.annotation.PreDestroy} annotation. */ public void setDestroyAnnotationType(Class destroyAnnotationType) { this.destroyAnnotationType = destroyAnnotationType; diff --git a/spring-context/spring-context.gradle b/spring-context/spring-context.gradle index 9e4cf72ca95..f7bb843fcc1 100644 --- a/spring-context/spring-context.gradle +++ b/spring-context/spring-context.gradle @@ -14,9 +14,8 @@ dependencies { optional("jakarta.enterprise.concurrent:jakarta.enterprise.concurrent-api") optional("jakarta.inject:jakarta.inject-api") optional("jakarta.interceptor:jakarta.interceptor-api") - optional("javax.money:money-api") optional("jakarta.validation:jakarta.validation-api") - optional("jakarta.xml.ws:jakarta.xml.ws-api") + optional("javax.money:money-api") optional("org.aspectj:aspectjweaver") optional("org.codehaus.groovy:groovy") optional("org.apache-extras.beanshell:bsh") @@ -32,8 +31,8 @@ dependencies { testImplementation("org.codehaus.groovy:groovy-test") testImplementation("org.codehaus.groovy:groovy-xml") testImplementation("org.apache.commons:commons-pool2") - testImplementation("jakarta.inject:jakarta.inject-tck") testImplementation("org.awaitility:awaitility") + testImplementation("jakarta.inject:jakarta.inject-tck") testRuntimeOnly("jakarta.xml.bind:jakarta.xml.bind-api") testRuntimeOnly("org.glassfish:jakarta.el") // Substitute for javax.management:jmxremote_optional:1.0.1_04 (not available on Maven Central) diff --git a/spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java b/spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java index 9c253124eea..20ed51eff6d 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ import java.util.Set; import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor; +import org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; @@ -91,11 +92,17 @@ public abstract class AnnotationConfigUtils { "org.springframework.context.annotation.internalRequiredAnnotationProcessor"; /** - * The bean name of the internally managed JSR-250 annotation processor. + * The bean name of the internally managed common annotation processor. */ public static final String COMMON_ANNOTATION_PROCESSOR_BEAN_NAME = "org.springframework.context.annotation.internalCommonAnnotationProcessor"; + /** + * The bean name of the internally managed JSR-250 annotation processor. + */ + private static final String JSR250_ANNOTATION_PROCESSOR_BEAN_NAME = + "org.springframework.context.annotation.internalJsr250AnnotationProcessor"; + /** * The bean name of the internally managed JPA annotation processor. */ @@ -117,16 +124,18 @@ public abstract class AnnotationConfigUtils { public static final String EVENT_LISTENER_FACTORY_BEAN_NAME = "org.springframework.context.event.internalEventListenerFactory"; - private static final boolean jsr250Present; - private static final boolean jpaPresent; + private static final ClassLoader classLoader = AnnotationConfigUtils.class.getClassLoader(); - static { - ClassLoader classLoader = AnnotationConfigUtils.class.getClassLoader(); - jsr250Present = ClassUtils.isPresent("jakarta.annotation.Resource", classLoader); - jpaPresent = ClassUtils.isPresent("jakarta.persistence.EntityManagerFactory", classLoader) && - ClassUtils.isPresent(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, classLoader); - } + private static final boolean jakartaAnnotationsPresent = + ClassUtils.isPresent("jakarta.annotation.PostConstruct", classLoader); + + private static final boolean jsr250Present = + ClassUtils.isPresent("javax.annotation.PostConstruct", classLoader); + + private static final boolean jpaPresent = + ClassUtils.isPresent("jakarta.persistence.EntityManagerFactory", classLoader) && + ClassUtils.isPresent(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, classLoader); /** @@ -172,13 +181,28 @@ public abstract class AnnotationConfigUtils { beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)); } - // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor. - if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) { + // Check for Jakarta Annotations support, and if present add the CommonAnnotationBeanPostProcessor. + if (jakartaAnnotationsPresent && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)); } + // Check for JSR-250 support, and if present add an InitDestroyAnnotationBeanPostProcessor + // for the javax variant of PostConstruct/PreDestroy. + if (jsr250Present && !registry.containsBeanDefinition(JSR250_ANNOTATION_PROCESSOR_BEAN_NAME)) { + try { + RootBeanDefinition def = new RootBeanDefinition(InitDestroyAnnotationBeanPostProcessor.class); + def.getPropertyValues().add("initAnnotationType", classLoader.loadClass("javax.annotation.PostConstruct")); + def.getPropertyValues().add("destroyAnnotationType", classLoader.loadClass("javax.annotation.PreDestroy")); + def.setSource(source); + beanDefs.add(registerPostProcessor(registry, def, JSR250_ANNOTATION_PROCESSOR_BEAN_NAME)); + } + catch (ClassNotFoundException ex) { + // Failed to load javax variants of the annotation types -> ignore. + } + } + // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor. if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(); diff --git a/spring-context/src/main/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessor.java b/spring-context/src/main/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessor.java index 75b7d08afec..3bd70bc53cb 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessor.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,13 +21,10 @@ import java.beans.PropertyDescriptor; import java.io.Serializable; import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; -import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.net.MalformedURLException; -import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; @@ -37,15 +34,10 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import javax.xml.namespace.QName; - import jakarta.annotation.PostConstruct; import jakarta.annotation.PreDestroy; import jakarta.annotation.Resource; import jakarta.ejb.EJB; -import jakarta.xml.ws.Service; -import jakarta.xml.ws.WebServiceClient; -import jakarta.xml.ws.WebServiceRef; import org.springframework.aop.TargetSource; import org.springframework.aop.framework.ProxyFactory; @@ -77,10 +69,9 @@ import org.springframework.util.StringValueResolver; /** * {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation - * that supports common Java annotations out of the box, in particular the JSR-250 + * that supports common Java annotations out of the box, in particular the common * annotations in the {@code jakarta.annotation} package. These common Java - * annotations are supported in many Jakarta EE technologies (e.g. JSF 1.2), - * as well as in Java 6's JAX-WS. + * annotations are supported in many Jakarta EE technologies (e.g. JSF and JAX-RS). * *

This post-processor includes support for the {@link jakarta.annotation.PostConstruct} * and {@link jakarta.annotation.PreDestroy} annotations - as init annotation @@ -95,12 +86,8 @@ import org.springframework.util.StringValueResolver; * and default names as well. The target beans can be simple POJOs, with no special * requirements other than the type having to match. * - *

The JAX-WS {@link javax.xml.ws.WebServiceRef} annotation is supported too, - * analogous to {@link jakarta.annotation.Resource} but with the capability of creating - * specific JAX-WS service endpoints. This may either point to an explicitly defined - * resource by name or operate on a locally specified JAX-WS service class. Finally, - * this post-processor also supports the EJB 3 {@link jakarta.ejb.EJB} annotation, - * analogous to {@link jakarta.annotation.Resource} as well, with the capability to + *

This post-processor also supports the EJB 3 {@link jakarta.ejb.EJB} annotation, + * analogous to {@link jakarta.annotation.Resource}, with the capability to * specify both a local bean name and a global JNDI name for fallback retrieval. * The target beans can be plain POJOs as well as EJB 3 Session Beans in this case. * @@ -143,22 +130,15 @@ import org.springframework.util.StringValueResolver; public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor implements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable { - @Nullable - private static final Class webServiceRefClass; + private static final Set> resourceAnnotationTypes = new LinkedHashSet<>(4); @Nullable private static final Class ejbClass; - private static final Set> resourceAnnotationTypes = new LinkedHashSet<>(4); - static { - webServiceRefClass = loadAnnotationType("javax.xml.ws.WebServiceRef"); - ejbClass = loadAnnotationType("jakarta.ejb.EJB"); - resourceAnnotationTypes.add(Resource.class); - if (webServiceRefClass != null) { - resourceAnnotationTypes.add(webServiceRefClass); - } + + ejbClass = loadAnnotationType("jakarta.ejb.EJB"); if (ejbClass != null) { resourceAnnotationTypes.add(ejbClass); } @@ -195,15 +175,11 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean setOrder(Ordered.LOWEST_PRECEDENCE - 3); setInitAnnotationType(PostConstruct.class); setDestroyAnnotationType(PreDestroy.class); - ignoreResourceType("javax.xml.ws.WebServiceContext"); } /** - * Ignore the given resource type when resolving {@code @Resource} - * annotations. - *

By default, the {@code javax.xml.ws.WebServiceContext} interface - * will be ignored, since it will be resolved by the JAX-WS runtime. + * Ignore the given resource type when resolving {@code @Resource} annotations. * @param resourceType the resource type to ignore */ public void ignoreResourceType(String resourceType) { @@ -361,13 +337,7 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean final List currElements = new ArrayList<>(); ReflectionUtils.doWithLocalFields(targetClass, field -> { - if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) { - if (Modifier.isStatic(field.getModifiers())) { - throw new IllegalStateException("@WebServiceRef annotation is not supported on static fields"); - } - currElements.add(new WebServiceRefElement(field, field, null)); - } - else if (ejbClass != null && field.isAnnotationPresent(ejbClass)) { + if (ejbClass != null && field.isAnnotationPresent(ejbClass)) { if (Modifier.isStatic(field.getModifiers())) { throw new IllegalStateException("@EJB annotation is not supported on static fields"); } @@ -389,17 +359,7 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean return; } if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) { - if (webServiceRefClass != null && bridgedMethod.isAnnotationPresent(webServiceRefClass)) { - if (Modifier.isStatic(method.getModifiers())) { - throw new IllegalStateException("@WebServiceRef annotation is not supported on static methods"); - } - if (method.getParameterCount() != 1) { - throw new IllegalStateException("@WebServiceRef annotation requires a single-arg method: " + method); - } - PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz); - currElements.add(new WebServiceRefElement(method, bridgedMethod, pd)); - } - else if (ejbClass != null && bridgedMethod.isAnnotationPresent(ejbClass)) { + if (ejbClass != null && bridgedMethod.isAnnotationPresent(ejbClass)) { if (Modifier.isStatic(method.getModifiers())) { throw new IllegalStateException("@EJB annotation is not supported on static methods"); } @@ -649,91 +609,6 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean } - /** - * Class representing injection information about an annotated field - * or setter method, supporting the @WebServiceRef annotation. - */ - private class WebServiceRefElement extends LookupElement { - - private final Class elementType; - - private final String wsdlLocation; - - public WebServiceRefElement(Member member, AnnotatedElement ae, @Nullable PropertyDescriptor pd) { - super(member, pd); - WebServiceRef resource = ae.getAnnotation(WebServiceRef.class); - String resourceName = resource.name(); - Class resourceType = resource.type(); - this.isDefaultName = !StringUtils.hasLength(resourceName); - if (this.isDefaultName) { - resourceName = this.member.getName(); - if (this.member instanceof Method && resourceName.startsWith("set") && resourceName.length() > 3) { - resourceName = Introspector.decapitalize(resourceName.substring(3)); - } - } - if (Object.class != resourceType) { - checkResourceType(resourceType); - } - else { - // No resource type specified... check field/method. - resourceType = getResourceType(); - } - this.name = resourceName; - this.elementType = resourceType; - if (Service.class.isAssignableFrom(resourceType)) { - this.lookupType = resourceType; - } - else { - this.lookupType = resource.value(); - } - this.mappedName = resource.mappedName(); - this.wsdlLocation = resource.wsdlLocation(); - } - - @Override - protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) { - Service service; - try { - service = (Service) getResource(this, requestingBeanName); - } - catch (NoSuchBeanDefinitionException notFound) { - // Service to be created through generated class. - if (Service.class == this.lookupType) { - throw new IllegalStateException("No resource with name '" + this.name + "' found in context, " + - "and no specific JAX-WS Service subclass specified. The typical solution is to either specify " + - "a LocalJaxWsServiceFactoryBean with the given name or to specify the (generated) Service " + - "subclass as @WebServiceRef(...) value."); - } - if (StringUtils.hasLength(this.wsdlLocation)) { - try { - Constructor ctor = this.lookupType.getConstructor(URL.class, QName.class); - WebServiceClient clientAnn = this.lookupType.getAnnotation(WebServiceClient.class); - if (clientAnn == null) { - throw new IllegalStateException("JAX-WS Service class [" + this.lookupType.getName() + - "] does not carry a WebServiceClient annotation"); - } - service = (Service) BeanUtils.instantiateClass(ctor, - new URL(this.wsdlLocation), new QName(clientAnn.targetNamespace(), clientAnn.name())); - } - catch (NoSuchMethodException ex) { - throw new IllegalStateException("JAX-WS Service class [" + this.lookupType.getName() + - "] does not have a (URL, QName) constructor. Cannot apply specified WSDL location [" + - this.wsdlLocation + "]."); - } - catch (MalformedURLException ex) { - throw new IllegalArgumentException( - "Specified WSDL location [" + this.wsdlLocation + "] isn't a valid URL"); - } - } - else { - service = (Service) BeanUtils.instantiateClass(this.lookupType); - } - } - return service.getPort(this.elementType); - } - } - - /** * Class representing injection information about an annotated field * or setter method, supporting the @EJB annotation. diff --git a/spring-context/src/test/java/org/springframework/context/annotation/ClassPathBeanDefinitionScannerTests.java b/spring-context/src/test/java/org/springframework/context/annotation/ClassPathBeanDefinitionScannerTests.java index cfb389e6a46..99f604181d5 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/ClassPathBeanDefinitionScannerTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/ClassPathBeanDefinitionScannerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -61,7 +61,7 @@ public class ClassPathBeanDefinitionScannerTests { GenericApplicationContext context = new GenericApplicationContext(); ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context); int beanCount = scanner.scan(BASE_PACKAGE); - assertThat(beanCount).isEqualTo(12); + assertThat(beanCount).isGreaterThanOrEqualTo(12); assertThat(context.containsBean("serviceInvocationCounter")).isTrue(); assertThat(context.containsBean("fooServiceImpl")).isTrue(); assertThat(context.containsBean("stubFooDao")).isTrue(); @@ -110,7 +110,7 @@ public class ClassPathBeanDefinitionScannerTests { ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context); int beanCount = scanner.scan(BASE_PACKAGE); - assertThat(beanCount).isEqualTo(12); + assertThat(beanCount).isGreaterThanOrEqualTo(12); ClassPathBeanDefinitionScanner scanner2 = new ClassPathBeanDefinitionScanner(context) { @Override @@ -138,7 +138,7 @@ public class ClassPathBeanDefinitionScannerTests { ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context); int beanCount = scanner.scan(BASE_PACKAGE); - assertThat(beanCount).isEqualTo(12); + assertThat(beanCount).isGreaterThanOrEqualTo(12); assertThat(context.containsBean("serviceInvocationCounter")).isTrue(); assertThat(context.containsBean("fooServiceImpl")).isTrue(); @@ -157,7 +157,7 @@ public class ClassPathBeanDefinitionScannerTests { ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context); int beanCount = scanner.scan(BASE_PACKAGE); - assertThat(beanCount).isEqualTo(12); + assertThat(beanCount).isGreaterThanOrEqualTo(12); ClassPathBeanDefinitionScanner scanner2 = new ClassPathBeanDefinitionScanner(context) { @Override @@ -182,7 +182,7 @@ public class ClassPathBeanDefinitionScannerTests { ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context); scanner.setIncludeAnnotationConfig(false); int beanCount = scanner.scan(BASE_PACKAGE); - assertThat(beanCount).isEqualTo(7); + assertThat(beanCount).isGreaterThanOrEqualTo(7); assertThat(context.containsBean("serviceInvocationCounter")).isTrue(); assertThat(context.containsBean("fooServiceImpl")).isTrue(); @@ -222,7 +222,7 @@ public class ClassPathBeanDefinitionScannerTests { scanner.setIncludeAnnotationConfig(false); int scannedBeanCount = scanner.scan(BASE_PACKAGE); - assertThat(scannedBeanCount).isEqualTo(6); + assertThat(scannedBeanCount).isGreaterThanOrEqualTo(6); assertThat(context.getBeanDefinitionCount()).isEqualTo((initialBeanCount + scannedBeanCount)); assertThat(context.containsBean("serviceInvocationCounter")).isTrue(); assertThat(context.containsBean("fooServiceImpl")).isTrue(); @@ -242,7 +242,7 @@ public class ClassPathBeanDefinitionScannerTests { scanner.setIncludeAnnotationConfig(false); int scannedBeanCount = scanner.scan(BASE_PACKAGE); - assertThat(scannedBeanCount).isEqualTo(6); + assertThat(scannedBeanCount).isGreaterThanOrEqualTo(6); assertThat(context.getBeanDefinitionCount()).isEqualTo((initialBeanCount + scannedBeanCount)); assertThat(context.containsBean("serviceInvocationCounter")).isTrue(); assertThat(context.containsBean("fooServiceImpl")).isTrue(); @@ -281,7 +281,7 @@ public class ClassPathBeanDefinitionScannerTests { scanner.addIncludeFilter(new AnnotationTypeFilter(CustomComponent.class)); int beanCount = scanner.scan(BASE_PACKAGE); - assertThat(beanCount).isEqualTo(6); + assertThat(beanCount).isGreaterThanOrEqualTo(6); assertThat(context.containsBean("messageBean")).isTrue(); assertThat(context.containsBean(AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)).isTrue(); assertThat(context.containsBean(AnnotationConfigUtils.COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)).isTrue(); @@ -296,7 +296,7 @@ public class ClassPathBeanDefinitionScannerTests { scanner.addIncludeFilter(new AnnotationTypeFilter(CustomComponent.class)); int beanCount = scanner.scan(BASE_PACKAGE); - assertThat(beanCount).isEqualTo(6); + assertThat(beanCount).isGreaterThanOrEqualTo(6); assertThat(context.containsBean("messageBean")).isTrue(); assertThat(context.containsBean("serviceInvocationCounter")).isFalse(); assertThat(context.containsBean("fooServiceImpl")).isFalse(); @@ -316,7 +316,7 @@ public class ClassPathBeanDefinitionScannerTests { scanner.addIncludeFilter(new AnnotationTypeFilter(CustomComponent.class)); int beanCount = scanner.scan(BASE_PACKAGE); - assertThat(beanCount).isEqualTo(13); + assertThat(beanCount).isGreaterThanOrEqualTo(13); assertThat(context.containsBean("messageBean")).isTrue(); assertThat(context.containsBean("serviceInvocationCounter")).isTrue(); assertThat(context.containsBean("fooServiceImpl")).isTrue(); @@ -336,7 +336,7 @@ public class ClassPathBeanDefinitionScannerTests { scanner.addExcludeFilter(new AnnotationTypeFilter(Aspect.class)); int beanCount = scanner.scan(BASE_PACKAGE); - assertThat(beanCount).isEqualTo(11); + assertThat(beanCount).isGreaterThanOrEqualTo(11); assertThat(context.containsBean("serviceInvocationCounter")).isFalse(); assertThat(context.containsBean("fooServiceImpl")).isTrue(); assertThat(context.containsBean("stubFooDao")).isTrue(); @@ -354,7 +354,7 @@ public class ClassPathBeanDefinitionScannerTests { scanner.addExcludeFilter(new AssignableTypeFilter(FooService.class)); int beanCount = scanner.scan(BASE_PACKAGE); - assertThat(beanCount).isEqualTo(11); + assertThat(beanCount).isGreaterThanOrEqualTo(11); assertThat(context.containsBean("fooServiceImpl")).isFalse(); assertThat(context.containsBean("serviceInvocationCounter")).isTrue(); assertThat(context.containsBean("stubFooDao")).isTrue(); @@ -374,7 +374,7 @@ public class ClassPathBeanDefinitionScannerTests { scanner.addExcludeFilter(new AssignableTypeFilter(FooService.class)); int beanCount = scanner.scan(BASE_PACKAGE); - assertThat(beanCount).isEqualTo(6); + assertThat(beanCount).isGreaterThanOrEqualTo(6); assertThat(context.containsBean("fooServiceImpl")).isFalse(); assertThat(context.containsBean("serviceInvocationCounter")).isTrue(); assertThat(context.containsBean("stubFooDao")).isTrue(); @@ -392,7 +392,7 @@ public class ClassPathBeanDefinitionScannerTests { scanner.addExcludeFilter(new AnnotationTypeFilter(Aspect.class)); int beanCount = scanner.scan(BASE_PACKAGE); - assertThat(beanCount).isEqualTo(10); + assertThat(beanCount).isGreaterThanOrEqualTo(10); assertThat(context.containsBean("fooServiceImpl")).isFalse(); assertThat(context.containsBean("serviceInvocationCounter")).isFalse(); assertThat(context.containsBean("stubFooDao")).isTrue(); @@ -411,7 +411,7 @@ public class ClassPathBeanDefinitionScannerTests { scanner.setBeanNameGenerator(new TestBeanNameGenerator()); int beanCount = scanner.scan(BASE_PACKAGE); - assertThat(beanCount).isEqualTo(12); + assertThat(beanCount).isGreaterThanOrEqualTo(12); assertThat(context.containsBean("fooServiceImpl")).isFalse(); assertThat(context.containsBean("fooService")).isTrue(); assertThat(context.containsBean("serviceInvocationCounter")).isTrue(); @@ -431,7 +431,7 @@ public class ClassPathBeanDefinitionScannerTests { GenericApplicationContext multiPackageContext = new GenericApplicationContext(); ClassPathBeanDefinitionScanner multiPackageScanner = new ClassPathBeanDefinitionScanner(multiPackageContext); int singlePackageBeanCount = singlePackageScanner.scan(BASE_PACKAGE); - assertThat(singlePackageBeanCount).isEqualTo(12); + assertThat(singlePackageBeanCount).isGreaterThanOrEqualTo(12); multiPackageScanner.scan(BASE_PACKAGE, "org.springframework.dao.annotation"); // assertTrue(multiPackageBeanCount > singlePackageBeanCount); } @@ -442,7 +442,7 @@ public class ClassPathBeanDefinitionScannerTests { ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context); int initialBeanCount = context.getBeanDefinitionCount(); int scannedBeanCount = scanner.scan(BASE_PACKAGE); - assertThat(scannedBeanCount).isEqualTo(12); + assertThat(scannedBeanCount).isGreaterThanOrEqualTo(12); assertThat((context.getBeanDefinitionCount() - initialBeanCount)).isEqualTo(scannedBeanCount); int addedBeanCount = scanner.scan("org.springframework.aop.aspectj.annotation"); assertThat(context.getBeanDefinitionCount()).isEqualTo((initialBeanCount + scannedBeanCount + addedBeanCount)); @@ -455,7 +455,7 @@ public class ClassPathBeanDefinitionScannerTests { ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context); scanner.setBeanNameGenerator(new TestBeanNameGenerator()); int beanCount = scanner.scan(BASE_PACKAGE); - assertThat(beanCount).isEqualTo(12); + assertThat(beanCount).isGreaterThanOrEqualTo(12); context.refresh(); FooServiceImpl fooService = context.getBean("fooService", FooServiceImpl.class); @@ -485,7 +485,7 @@ public class ClassPathBeanDefinitionScannerTests { scanner.setIncludeAnnotationConfig(false); scanner.setBeanNameGenerator(new TestBeanNameGenerator()); int beanCount = scanner.scan(BASE_PACKAGE); - assertThat(beanCount).isEqualTo(7); + assertThat(beanCount).isGreaterThanOrEqualTo(7); context.refresh(); try {