diff --git a/framework-platform/framework-platform.gradle b/framework-platform/framework-platform.gradle index 88e1ec38e77..5d2e712558e 100644 --- a/framework-platform/framework-platform.gradle +++ b/framework-platform/framework-platform.gradle @@ -26,7 +26,7 @@ dependencies { constraints { api("com.fasterxml:aalto-xml:1.3.4") api("com.fasterxml.woodstox:woodstox-core:6.7.0") - api("com.github.ben-manes.caffeine:caffeine:3.2.2") + api("com.github.ben-manes.caffeine:caffeine:3.2.3") api("com.github.librepdf:openpdf:1.3.43") api("com.google.code.findbugs:findbugs:3.0.1") api("com.google.code.findbugs:jsr305:3.0.2") @@ -124,7 +124,7 @@ dependencies { api("org.hibernate.orm:hibernate-core:7.2.0.CR1") api("org.hibernate.validator:hibernate-validator:9.1.0.CR1") api("org.hsqldb:hsqldb:2.7.4") - api("org.htmlunit:htmlunit:4.17.0") + api("org.htmlunit:htmlunit:4.18.0") api("org.javamoney:moneta:1.4.4") api("org.jboss.logging:jboss-logging:3.6.1.Final") api("org.jruby:jruby:10.0.2.0") @@ -135,8 +135,8 @@ dependencies { api("org.python:jython-standalone:2.7.4") api("org.quartz-scheduler:quartz:2.3.2") api("org.reactivestreams:reactive-streams:1.0.4") - api("org.seleniumhq.selenium:htmlunit3-driver:4.36.1") - api("org.seleniumhq.selenium:selenium-java:4.36.0") + api("org.seleniumhq.selenium:htmlunit3-driver:4.38.0") + api("org.seleniumhq.selenium:selenium-java:4.38.0") api("org.skyscreamer:jsonassert:1.5.3") api("org.testng:testng:7.11.0") api("org.webjars:underscorejs:1.8.3") diff --git a/spring-context/src/main/java/org/springframework/cache/annotation/CachingConfigurer.java b/spring-context/src/main/java/org/springframework/cache/annotation/CachingConfigurer.java index fea24a03fc9..37ffbd4149d 100644 --- a/spring-context/src/main/java/org/springframework/cache/annotation/CachingConfigurer.java +++ b/spring-context/src/main/java/org/springframework/cache/annotation/CachingConfigurer.java @@ -24,14 +24,14 @@ import org.springframework.cache.interceptor.CacheResolver; import org.springframework.cache.interceptor.KeyGenerator; /** - * Interface to be implemented by @{@link org.springframework.context.annotation.Configuration - * Configuration} classes annotated with @{@link EnableCaching} that wish or need to specify - * explicitly how caches are resolved and how keys are generated for annotation-driven - * cache management. + * Interface to be implemented for explicitly specifying how caches are resolved + * and how keys are generated for annotation-driven cache management. * - *

See @{@link EnableCaching} for general examples and context; see - * {@link #cacheManager()}, {@link #cacheResolver()}, {@link #keyGenerator()}, and - * {@link #errorHandler()} for detailed instructions. + *

Typically implemented by @{@link org.springframework.context.annotation.Configuration + * Configuration} classes annotated with @{@link EnableCaching}. + * See @{@link EnableCaching} for general examples and context; see + * {@link #cacheManager()}, {@link #cacheResolver()}, {@link #keyGenerator()}, + * and {@link #errorHandler()} for detailed instructions. * *

NOTE: A {@code CachingConfigurer} will get initialized early. * Do not inject common dependencies into autowired fields directly; instead, consider diff --git a/spring-context/src/main/java/org/springframework/scheduling/annotation/AsyncConfigurer.java b/spring-context/src/main/java/org/springframework/scheduling/annotation/AsyncConfigurer.java index 6850303e772..f259b22bd25 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/annotation/AsyncConfigurer.java +++ b/spring-context/src/main/java/org/springframework/scheduling/annotation/AsyncConfigurer.java @@ -23,13 +23,18 @@ import org.jspecify.annotations.Nullable; import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; /** - * Interface to be implemented by @{@link org.springframework.context.annotation.Configuration - * Configuration} classes annotated with @{@link EnableAsync} that wish to customize the - * {@link Executor} instance used when processing async method invocations or the - * {@link AsyncUncaughtExceptionHandler} instance used to process exception thrown from - * async method with {@code void} return type. + * Interface to be implemented for customizing the {@link Executor} instance used when + * processing async method invocations or the {@link AsyncUncaughtExceptionHandler} + * instance used to process exceptions thrown from async methods with a {@code void} + * return type. * - *

See @{@link EnableAsync} for usage examples. + *

Typically implemented by @{@link org.springframework.context.annotation.Configuration + * Configuration} classes annotated with @{@link EnableAsync}. + * See the @{@link EnableAsync} javadoc for usage examples. + * + *

NOTE: An {@code AsyncConfigurer} will get initialized early. + * Do not inject common dependencies into autowired fields directly; instead, consider + * declaring a lazy {@link org.springframework.beans.factory.ObjectProvider} for those. * * @author Chris Beams * @author Stephane Nicoll diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessor.java b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessor.java index c4ccbad1ddf..c6f52fd611f 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessor.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessor.java @@ -65,7 +65,6 @@ import org.springframework.util.ReflectionUtils; * @author Sebastien Deleuze * @since 6.0 */ -@SuppressWarnings("unchecked") class PersistenceManagedTypesBeanRegistrationAotProcessor implements BeanRegistrationAotProcessor { private static final boolean JPA_PRESENT = ClassUtils.isPresent("jakarta.persistence.Entity", @@ -82,12 +81,12 @@ class PersistenceManagedTypesBeanRegistrationAotProcessor implements BeanRegistr return null; } + private static final class JpaManagedTypesBeanRegistrationCodeFragments extends BeanRegistrationCodeFragmentsDecorator { private static final List> CALLBACK_TYPES = List.of(PreUpdate.class, PostUpdate.class, PrePersist.class, PostPersist.class, PreRemove.class, PostRemove.class, PostLoad.class); - private static final ParameterizedTypeName LIST_OF_STRINGS_TYPE = ParameterizedTypeName.get(List.class, String.class); private final RegisteredBean registeredBean; @@ -102,8 +101,8 @@ class PersistenceManagedTypesBeanRegistrationAotProcessor implements BeanRegistr @Override public CodeBlock generateInstanceSupplierCode(GenerationContext generationContext, - BeanRegistrationCode beanRegistrationCode, - boolean allowDirectSupplierShortcut) { + BeanRegistrationCode beanRegistrationCode, boolean allowDirectSupplierShortcut) { + PersistenceManagedTypes persistenceManagedTypes = this.registeredBean.getBeanFactory() .getBean(this.registeredBean.getBeanName(), PersistenceManagedTypes.class); contributeHints(generationContext.getRuntimeHints(), @@ -140,7 +139,7 @@ class PersistenceManagedTypesBeanRegistrationAotProcessor implements BeanRegistr contributeHibernateHints(hints, classLoader, managedClass); } catch (ClassNotFoundException ex) { - throw new IllegalArgumentException("Failed to instantiate the managed class: " + managedClassName, ex); + throw new IllegalArgumentException("Failed to instantiate JPA managed class: " + managedClassName, ex); } } } @@ -149,7 +148,8 @@ class PersistenceManagedTypesBeanRegistrationAotProcessor implements BeanRegistr EntityListeners entityListeners = AnnotationUtils.findAnnotation(managedClass, EntityListeners.class); if (entityListeners != null) { for (Class entityListener : entityListeners.value()) { - hints.reflection().registerType(entityListener, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_PUBLIC_METHODS); + hints.reflection().registerType(entityListener, + MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_PUBLIC_METHODS); } } } @@ -169,12 +169,14 @@ class PersistenceManagedTypesBeanRegistrationAotProcessor implements BeanRegistr } Convert convertClassAnnotation = AnnotationUtils.findAnnotation(managedClass, Convert.class); if (convertClassAnnotation != null) { - reflectionHints.registerType(convertClassAnnotation.converter(), MemberCategory.INVOKE_DECLARED_CONSTRUCTORS); + reflectionHints.registerType(convertClassAnnotation.converter(), + MemberCategory.INVOKE_DECLARED_CONSTRUCTORS); } ReflectionUtils.doWithFields(managedClass, field -> { Convert convertFieldAnnotation = AnnotationUtils.findAnnotation(field, Convert.class); if (convertFieldAnnotation != null && convertFieldAnnotation.converter() != AttributeConverter.class) { - reflectionHints.registerType(convertFieldAnnotation.converter(), MemberCategory.INVOKE_DECLARED_CONSTRUCTORS); + reflectionHints.registerType(convertFieldAnnotation.converter(), + MemberCategory.INVOKE_DECLARED_CONSTRUCTORS); } }); } @@ -186,11 +188,11 @@ class PersistenceManagedTypesBeanRegistrationAotProcessor implements BeanRegistr method -> CALLBACK_TYPES.stream().anyMatch(method::isAnnotationPresent)); } - @SuppressWarnings("unchecked") private void contributeHibernateHints(RuntimeHints hints, @Nullable ClassLoader classLoader, Class managedClass) { ReflectionHints reflection = hints.reflection(); - Class embeddableInstantiatorClass = loadClass("org.hibernate.annotations.EmbeddableInstantiator", classLoader); + Class embeddableInstantiatorClass = + loadClass("org.hibernate.annotations.EmbeddableInstantiator", classLoader); if (embeddableInstantiatorClass != null) { registerForReflection(reflection, AnnotationUtils.findAnnotation(managedClass, embeddableInstantiatorClass), "value"); @@ -204,7 +206,8 @@ class PersistenceManagedTypesBeanRegistrationAotProcessor implements BeanRegistr AnnotationUtils.findAnnotation(method, embeddableInstantiatorClass), "value")); } - Class valueGenerationTypeClass = loadClass("org.hibernate.annotations.ValueGenerationType", classLoader); + Class valueGenerationTypeClass = + loadClass("org.hibernate.annotations.ValueGenerationType", classLoader); if (valueGenerationTypeClass != null) { ReflectionUtils.doWithFields(managedClass, field -> registerForReflection(reflection, AnnotationUtils.findAnnotation(field, valueGenerationTypeClass), "generatedBy")); @@ -212,7 +215,8 @@ class PersistenceManagedTypesBeanRegistrationAotProcessor implements BeanRegistr AnnotationUtils.findAnnotation(method, valueGenerationTypeClass), "generatedBy")); } - Class idGeneratorTypeClass = loadClass("org.hibernate.annotations.IdGeneratorType", classLoader); + Class idGeneratorTypeClass = + loadClass("org.hibernate.annotations.IdGeneratorType", classLoader); if (idGeneratorTypeClass != null) { ReflectionUtils.doWithFields(managedClass, field -> registerForReflection(reflection, AnnotationUtils.findAnnotation(field, idGeneratorTypeClass), "value")); @@ -220,7 +224,8 @@ class PersistenceManagedTypesBeanRegistrationAotProcessor implements BeanRegistr AnnotationUtils.findAnnotation(method, idGeneratorTypeClass), "value")); } - Class attributeBinderTypeClass = loadClass("org.hibernate.annotations.AttributeBinderType", classLoader); + Class attributeBinderTypeClass = + loadClass("org.hibernate.annotations.AttributeBinderType", classLoader); if (attributeBinderTypeClass != null) { ReflectionUtils.doWithFields(managedClass, field -> registerForReflection(reflection, AnnotationUtils.findAnnotation(field, attributeBinderTypeClass), "binder")); @@ -229,6 +234,7 @@ class PersistenceManagedTypesBeanRegistrationAotProcessor implements BeanRegistr } } + @SuppressWarnings("unchecked") private static @Nullable Class loadClass(String className, @Nullable ClassLoader classLoader) { try { return (Class) ClassUtils.forName(className, classLoader); @@ -238,7 +244,7 @@ class PersistenceManagedTypesBeanRegistrationAotProcessor implements BeanRegistr } } - @SuppressWarnings("NullAway") // Not null assertion performed in ReflectionHints.registerType + @SuppressWarnings("NullAway") // Not-null assertion performed in ReflectionHints.registerType private void registerForReflection(ReflectionHints reflection, @Nullable Annotation annotation, String attribute) { if (annotation == null) { return; @@ -247,4 +253,5 @@ class PersistenceManagedTypesBeanRegistrationAotProcessor implements BeanRegistr reflection.registerType(type, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS); } } + } diff --git a/spring-orm/src/test/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessorTests.java b/spring-orm/src/test/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessorTests.java index 725c101bfda..6b45c4c81fb 100644 --- a/spring-orm/src/test/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessorTests.java +++ b/spring-orm/src/test/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessorTests.java @@ -66,8 +66,7 @@ class PersistenceManagedTypesBeanRegistrationAotProcessorTests { GenericApplicationContext context = new AnnotationConfigApplicationContext(); context.registerBean(JpaDomainConfiguration.class); compile(context, (initializer, compiled) -> { - GenericApplicationContext freshApplicationContext = toFreshApplicationContext( - initializer); + GenericApplicationContext freshApplicationContext = toFreshApplicationContext(initializer); PersistenceManagedTypes persistenceManagedTypes = freshApplicationContext.getBean( "persistenceManagedTypes", PersistenceManagedTypes.class); assertThat(persistenceManagedTypes.getManagedClassNames()).containsExactlyInAnyOrder( @@ -121,6 +120,7 @@ class PersistenceManagedTypesBeanRegistrationAotProcessorTests { @SuppressWarnings("unchecked") private void compile(GenericApplicationContext applicationContext, BiConsumer, Compiled> result) { + ApplicationContextAotGenerator generator = new ApplicationContextAotGenerator(); TestGenerationContext generationContext = new TestGenerationContext(); generator.processAheadOfTime(applicationContext, generationContext); @@ -131,6 +131,7 @@ class PersistenceManagedTypesBeanRegistrationAotProcessorTests { private GenericApplicationContext toFreshApplicationContext( ApplicationContextInitializer initializer) { + GenericApplicationContext freshApplicationContext = new GenericApplicationContext(); initializer.initialize(freshApplicationContext); freshApplicationContext.refresh(); @@ -145,24 +146,6 @@ class PersistenceManagedTypesBeanRegistrationAotProcessorTests { } - public static class JpaDomainConfiguration extends AbstractEntityManagerWithPackagesToScanConfiguration { - - @Override - protected String packageToScan() { - return "org.springframework.orm.jpa.domain"; - } - } - - - public static class HibernateDomainConfiguration extends AbstractEntityManagerWithPackagesToScanConfiguration { - - @Override - protected String packageToScan() { - return "org.springframework.orm.jpa.hibernate.domain"; - } - } - - public abstract static class AbstractEntityManagerWithPackagesToScanConfiguration { protected boolean scanningInvoked; @@ -182,13 +165,13 @@ class PersistenceManagedTypesBeanRegistrationAotProcessorTests { @Bean public PersistenceManagedTypes persistenceManagedTypes(ResourceLoader resourceLoader) { this.scanningInvoked = true; - return new PersistenceManagedTypesScanner(resourceLoader) - .scan(packageToScan()); + return new PersistenceManagedTypesScanner(resourceLoader).scan(packageToScan()); } @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource, JpaVendorAdapter jpaVendorAdapter, PersistenceManagedTypes persistenceManagedTypes) { + LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean(); entityManagerFactoryBean.setDataSource(dataSource); entityManagerFactoryBean.setJpaVendorAdapter(jpaVendorAdapter); @@ -199,4 +182,22 @@ class PersistenceManagedTypesBeanRegistrationAotProcessorTests { protected abstract String packageToScan(); } + + public static class JpaDomainConfiguration extends AbstractEntityManagerWithPackagesToScanConfiguration { + + @Override + protected String packageToScan() { + return "org.springframework.orm.jpa.domain"; + } + } + + + public static class HibernateDomainConfiguration extends AbstractEntityManagerWithPackagesToScanConfiguration { + + @Override + protected String packageToScan() { + return "org.springframework.orm.jpa.hibernate.domain"; + } + } + } diff --git a/spring-tx/src/main/java/org/springframework/transaction/annotation/TransactionManagementConfigurer.java b/spring-tx/src/main/java/org/springframework/transaction/annotation/TransactionManagementConfigurer.java index 5c721b2d963..a56e655fb13 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/annotation/TransactionManagementConfigurer.java +++ b/spring-tx/src/main/java/org/springframework/transaction/annotation/TransactionManagementConfigurer.java @@ -19,15 +19,17 @@ package org.springframework.transaction.annotation; import org.springframework.transaction.TransactionManager; /** - * Interface to be implemented by @{@link org.springframework.context.annotation.Configuration - * Configuration} classes annotated with @{@link EnableTransactionManagement} that wish to - * (or need to) explicitly specify the default {@code PlatformTransactionManager} bean - * (or {@code ReactiveTransactionManager} bean) to be used for annotation-driven - * transaction management, as opposed to the default approach of a by-type lookup. - * One reason this might be necessary is if there are two {@code PlatformTransactionManager} - * beans (or two {@code ReactiveTransactionManager} beans) present in the container. + * Interface to be implemented for explicitly specifying the default + * {@link org.springframework.transaction.PlatformTransactionManager} bean + * (or {@link org.springframework.transaction.ReactiveTransactionManager} bean) + * to be used for annotation-driven transaction management, as opposed to the + * default approach of a by-type lookup. One reason this might be necessary is + * if there are two {@code PlatformTransactionManager} beans (or two + * {@code ReactiveTransactionManager} beans) present in the container. * - *

See @{@link EnableTransactionManagement} for general examples and context; + *

Typically implemented by @{@link org.springframework.context.annotation.Configuration + * Configuration} classes annotated with @{@link EnableTransactionManagement}. + * See @{@link EnableTransactionManagement} for general examples and context; * see {@link #annotationDrivenTransactionManager()} for detailed instructions. * *

NOTE: A {@code TransactionManagementConfigurer} will get initialized early.