From 88a60ec3c57ac9dc432a0074b9828551f19a0bb5 Mon Sep 17 00:00:00 2001 From: Dmytro Nosan Date: Mon, 28 Oct 2024 16:57:39 +0200 Subject: [PATCH] Introduce ImportTestContainersBeanFactoryInitializationAotProcessor that collects all importing classes and then generates an initializer method that invokes ImportTestcontainersRegistrar.registerBeanDefinitions(...) for those classes --- .../DynamicPropertySourceMethodsImporter.java | 162 ------------------ .../ImportTestcontainersRegistrar.java | 133 +++++++++++++- .../TestcontainerFieldBeanDefinition.java | 99 +---------- .../resources/META-INF/spring/aot.factories | 11 +- 4 files changed, 143 insertions(+), 262 deletions(-) diff --git a/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/context/DynamicPropertySourceMethodsImporter.java b/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/context/DynamicPropertySourceMethodsImporter.java index d11ba194571f..d680f7504c81 100644 --- a/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/context/DynamicPropertySourceMethodsImporter.java +++ b/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/context/DynamicPropertySourceMethodsImporter.java @@ -18,37 +18,16 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.util.Map; import java.util.Set; -import org.springframework.aot.generate.AccessControl; -import org.springframework.aot.generate.GeneratedClass; -import org.springframework.aot.generate.GeneratedMethod; -import org.springframework.aot.generate.GenerationContext; -import org.springframework.aot.generate.MethodReference.ArgumentCodeGenerator; -import org.springframework.aot.hint.ExecutableMode; -import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution; -import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor; -import org.springframework.beans.factory.aot.BeanFactoryInitializationCode; -import org.springframework.beans.factory.aot.BeanRegistrationExcludeFilter; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.beans.factory.support.DefaultListableBeanFactory; -import org.springframework.beans.factory.support.RegisteredBean; -import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.boot.testcontainers.properties.TestcontainersPropertySource; import org.springframework.core.MethodIntrospector; import org.springframework.core.annotation.MergedAnnotations; -import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.Environment; -import org.springframework.javapoet.ClassName; -import org.springframework.javapoet.CodeBlock; import org.springframework.test.context.DynamicPropertyRegistry; import org.springframework.test.context.DynamicPropertySource; -import org.springframework.test.util.ReflectionTestUtils; import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils; /** @@ -77,16 +56,6 @@ void registerDynamicPropertySources(BeanDefinitionRegistry beanDefinitionRegistr ReflectionUtils.makeAccessible(method); ReflectionUtils.invokeMethod(method, null, dynamicPropertyRegistry); }); - - String beanName = "importTestContainer.%s.%s".formatted(DynamicPropertySource.class.getName(), definitionClass); - if (!beanDefinitionRegistry.containsBeanDefinition(beanName)) { - RootBeanDefinition bd = new RootBeanDefinition(DynamicPropertySourceMetadata.class); - bd.setInstanceSupplier(() -> new DynamicPropertySourceMetadata(definitionClass, methods)); - bd.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - bd.setAutowireCandidate(false); - bd.setAttribute(DynamicPropertySourceMetadata.class.getName(), true); - beanDefinitionRegistry.registerBeanDefinition(beanName, bd); - } } private boolean isAnnotated(Method method) { @@ -102,135 +71,4 @@ private void assertValid(Method method) { + "' must accept a single DynamicPropertyRegistry argument"); } - private record DynamicPropertySourceMetadata(Class definitionClass, Set methods) { - } - - /** - * {@link BeanRegistrationExcludeFilter} to exclude - * {@link DynamicPropertySourceMetadata} from AOT bean registrations. - */ - static class DynamicPropertySourceMetadataBeanRegistrationExcludeFilter implements BeanRegistrationExcludeFilter { - - @Override - public boolean isExcludedFromAotProcessing(RegisteredBean registeredBean) { - return registeredBean.getMergedBeanDefinition().hasAttribute(DynamicPropertySourceMetadata.class.getName()); - } - - } - - /** - * The {@link BeanFactoryInitializationAotProcessor} generates methods for each - * {@code @DynamicPropertySource-annotated} method. - * - */ - static class DynamicPropertySourceBeanFactoryInitializationAotProcessor - implements BeanFactoryInitializationAotProcessor { - - private static final String DYNAMIC_PROPERTY_REGISTRY = "dynamicPropertyRegistry"; - - @Override - public BeanFactoryInitializationAotContribution processAheadOfTime( - ConfigurableListableBeanFactory beanFactory) { - Map metadata = beanFactory - .getBeansOfType(DynamicPropertySourceMetadata.class, false, false); - if (metadata.isEmpty()) { - return null; - } - return new AotContibution(metadata); - } - - private static final class AotContibution implements BeanFactoryInitializationAotContribution { - - private final Map metadata; - - private AotContibution(Map metadata) { - this.metadata = metadata; - } - - @Override - public void applyTo(GenerationContext generationContext, - BeanFactoryInitializationCode beanFactoryInitializationCode) { - GeneratedMethod initializerMethod = beanFactoryInitializationCode.getMethods() - .add("registerDynamicPropertySources", (code) -> { - code.addJavadoc("Registers {@code @DynamicPropertySource} properties"); - code.addParameter(ConfigurableEnvironment.class, "environment"); - code.addParameter(DefaultListableBeanFactory.class, "beanFactory"); - code.addModifiers(javax.lang.model.element.Modifier.PRIVATE, - javax.lang.model.element.Modifier.STATIC); - code.addStatement("$T dynamicPropertyRegistry = $T.attach(environment, beanFactory)", - DynamicPropertyRegistry.class, TestcontainersPropertySource.class); - this.metadata.forEach((name, metadata) -> { - GeneratedMethod dynamicPropertySourceMethod = generateMethods(generationContext, metadata); - code.addStatement(dynamicPropertySourceMethod.toMethodReference() - .toInvokeCodeBlock(ArgumentCodeGenerator.of(DynamicPropertyRegistry.class, - DYNAMIC_PROPERTY_REGISTRY))); - }); - }); - beanFactoryInitializationCode.addInitializer(initializerMethod.toMethodReference()); - } - - // Generates a new class in definition class package and invokes - // all @DynamicPropertySource methods. - private GeneratedMethod generateMethods(GenerationContext generationContext, - DynamicPropertySourceMetadata metadata) { - Class definitionClass = metadata.definitionClass(); - GeneratedClass generatedClass = generationContext.getGeneratedClasses() - .addForFeatureComponent(DynamicPropertySource.class.getSimpleName(), definitionClass, - (code) -> code.addModifiers(javax.lang.model.element.Modifier.PUBLIC)); - return generatedClass.getMethods().add("registerDynamicPropertySource", (code) -> { - code.addJavadoc("Registers {@code @DynamicPropertySource} properties for class '$T'", - definitionClass); - code.addParameter(DynamicPropertyRegistry.class, DYNAMIC_PROPERTY_REGISTRY); - code.addModifiers(javax.lang.model.element.Modifier.PUBLIC, - javax.lang.model.element.Modifier.STATIC); - metadata.methods().forEach((method) -> { - GeneratedMethod generateMethod = generateMethod(generationContext, generatedClass, method); - code.addStatement(generateMethod.toMethodReference() - .toInvokeCodeBlock(ArgumentCodeGenerator.of(DynamicPropertyRegistry.class, - DYNAMIC_PROPERTY_REGISTRY))); - }); - }); - } - - // If the method is inaccessible, the reflection will be used; otherwise, - // direct call to the method will be used. - private static GeneratedMethod generateMethod(GenerationContext generationContext, - GeneratedClass generatedClass, Method method) { - return generatedClass.getMethods().add(method.getName(), (code) -> { - code.addJavadoc("Register {@code @DynamicPropertySource} for method '$T.$L'", - method.getDeclaringClass(), method.getName()); - code.addModifiers(javax.lang.model.element.Modifier.PRIVATE, - javax.lang.model.element.Modifier.STATIC); - code.addParameter(DynamicPropertyRegistry.class, DYNAMIC_PROPERTY_REGISTRY); - if (isMethodAccessible(generatedClass, method)) { - code.addStatement(CodeBlock.of("$T.$L($L)", method.getDeclaringClass(), method.getName(), - DYNAMIC_PROPERTY_REGISTRY)); - } - else { - generationContext.getRuntimeHints().reflection().registerMethod(method, ExecutableMode.INVOKE); - code.beginControlFlow("try"); - code.addStatement("$T clazz = $T.forName($S, $T.class.getClassLoader())", Class.class, - ClassUtils.class, ClassName.get(method.getDeclaringClass()), generatedClass.getName()); - // ReflectionTestUtils can be used here because - // @DynamicPropertyRegistry in a test module. - code.addStatement("$T.invokeMethod(clazz, $S, $L)", ReflectionTestUtils.class, method.getName(), - DYNAMIC_PROPERTY_REGISTRY); - code.nextControlFlow("catch ($T ex)", ClassNotFoundException.class); - code.addStatement("throw new $T(ex)", RuntimeException.class); - code.endControlFlow(); - } - }); - - } - - private static boolean isMethodAccessible(GeneratedClass generatedClass, Method method) { - ClassName className = generatedClass.getName(); - return AccessControl.forClass(method.getDeclaringClass()).isAccessibleFrom(className) - && AccessControl.forMember(method).isAccessibleFrom(className); - } - - } - - } - } diff --git a/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/context/ImportTestcontainersRegistrar.java b/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/context/ImportTestcontainersRegistrar.java index 1c2cf49725c3..8f64d9f89bf8 100644 --- a/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/context/ImportTestcontainersRegistrar.java +++ b/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/context/ImportTestcontainersRegistrar.java @@ -16,11 +16,34 @@ package org.springframework.boot.testcontainers.context; +import java.util.Arrays; +import java.util.LinkedHashSet; +import java.util.Set; + +import javax.lang.model.element.Modifier; + +import org.springframework.aot.AotDetector; +import org.springframework.aot.generate.GeneratedClass; +import org.springframework.aot.generate.GeneratedMethod; +import org.springframework.aot.generate.GenerationContext; +import org.springframework.aot.hint.MemberCategory; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution; +import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor; +import org.springframework.beans.factory.aot.BeanFactoryInitializationCode; +import org.springframework.beans.factory.aot.BeanRegistrationExcludeFilter; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.support.RegisteredBean; +import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.annotation.MergedAnnotation; +import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.Environment; import org.springframework.core.type.AnnotationMetadata; +import org.springframework.javapoet.ClassName; import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; @@ -51,13 +74,30 @@ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, B MergedAnnotation annotation = importingClassMetadata.getAnnotations() .get(ImportTestcontainers.class); Class[] definitionClasses = annotation.getClassArray(MergedAnnotation.VALUE); + Class importingClass = ClassUtils.resolveClassName(importingClassMetadata.getClassName(), null); if (ObjectUtils.isEmpty(definitionClasses)) { - Class importingClass = ClassUtils.resolveClassName(importingClassMetadata.getClassName(), null); definitionClasses = new Class[] { importingClass }; } + registerMetadataBeanDefinition(registry, importingClass, Set.copyOf(Arrays.asList(definitionClasses))); registerBeanDefinitions(registry, definitionClasses); } + private void registerMetadataBeanDefinition(BeanDefinitionRegistry registry, Class importingClass, + Set> definitionClasses) { + if (!AotDetector.useGeneratedArtifacts()) { + String beanName = "%s.%s.metadata".formatted(ImportTestcontainersRegistrar.class, importingClass.getName()); + if (registry.containsBeanDefinition(beanName)) { + return; + } + RootBeanDefinition bd = new RootBeanDefinition(ImportTestcontainersMetadata.class); + bd.setInstanceSupplier(() -> new ImportTestcontainersMetadata(importingClass, definitionClasses)); + bd.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + bd.setAutowireCandidate(false); + bd.setAttribute(ImportTestcontainersRegistrar.class.getName(), true); + registry.registerBeanDefinition(beanName, bd); + } + } + private void registerBeanDefinitions(BeanDefinitionRegistry registry, Class[] definitionClasses) { for (Class definitionClass : definitionClasses) { this.containerFieldsImporter.registerBeanDefinitions(registry, definitionClass); @@ -67,4 +107,95 @@ private void registerBeanDefinitions(BeanDefinitionRegistry registry, Class[] } } + private record ImportTestcontainersMetadata(Class importingClass, Set> definitionClasses) { + } + + static class ImportTestcontainersMetadataBeanRegistrationExcludeFilter implements BeanRegistrationExcludeFilter { + + @Override + public boolean isExcludedFromAotProcessing(RegisteredBean registeredBean) { + return registeredBean.getMergedBeanDefinition().hasAttribute(ImportTestcontainersRegistrar.class.getName()); + } + + } + + static class ImportTestcontainersBeanFactoryInitializationAotProcessor + implements BeanFactoryInitializationAotProcessor { + + @Override + public BeanFactoryInitializationAotContribution processAheadOfTime( + ConfigurableListableBeanFactory beanFactory) { + Set importClasses = new LinkedHashSet<>( + beanFactory.getBeansOfType(ImportTestcontainersMetadata.class, false, false).values()); + if (importClasses.isEmpty()) { + return null; + } + return new AotContibution(importClasses); + } + + private static final class AotContibution implements BeanFactoryInitializationAotContribution { + + private static final String BEAN_FACTORY_PARAM = "beanFactory"; + + private static final String ENVIRONMENT_PARAM = "environment"; + + private static final String IMPORTING_CLASS_PARAM = "importingClass"; + + private final Set metadata; + + private AotContibution(Set metadata) { + this.metadata = metadata; + } + + @Override + public void applyTo(GenerationContext generationContext, + BeanFactoryInitializationCode beanFactoryInitializationCode) { + + contributeHints(generationContext.getRuntimeHints()); + + GeneratedClass generatedClass = generationContext.getGeneratedClasses() + .addForFeatureComponent(ImportTestcontainers.class.getSimpleName(), + ImportTestcontainersRegistrar.class, (code) -> code.addModifiers(Modifier.PUBLIC)); + + GeneratedMethod importBeanDefinitionMethod = generateImportBeanDefinitionMethod(generatedClass); + GeneratedMethod initializeMethod = generatedClass.getMethods() + .add("registerBeanDefinitions", (code) -> { + code.addJavadoc("Register bean definitions for '$T'", ImportTestcontainers.class); + code.addModifiers(Modifier.PUBLIC, Modifier.STATIC); + code.addParameter(ConfigurableEnvironment.class, ENVIRONMENT_PARAM); + code.addParameter(DefaultListableBeanFactory.class, BEAN_FACTORY_PARAM); + this.metadata.forEach((metadata) -> code.addStatement("$L($L, $L, $S)", + importBeanDefinitionMethod.getName(), ENVIRONMENT_PARAM, BEAN_FACTORY_PARAM, + ClassName.get(metadata.importingClass()))); + }); + beanFactoryInitializationCode.addInitializer(initializeMethod.toMethodReference()); + } + + private void contributeHints(RuntimeHints runtimeHints) { + Set> definitionClasses = new LinkedHashSet<>(); + this.metadata.forEach((metadata) -> definitionClasses.addAll(metadata.definitionClasses())); + definitionClasses.forEach((definitionClass) -> runtimeHints.reflection() + .registerType(definitionClass, MemberCategory.DECLARED_FIELDS, MemberCategory.PUBLIC_FIELDS, + MemberCategory.INVOKE_PUBLIC_METHODS, MemberCategory.INVOKE_DECLARED_METHODS)); + } + + private GeneratedMethod generateImportBeanDefinitionMethod(GeneratedClass generatedClass) { + return generatedClass.getMethods().add("registerBeanDefinitionsFor", (code) -> { + code.addModifiers(Modifier.PRIVATE, Modifier.STATIC); + code.addParameter(ConfigurableEnvironment.class, ENVIRONMENT_PARAM); + code.addParameter(DefaultListableBeanFactory.class, BEAN_FACTORY_PARAM); + code.addParameter(String.class, IMPORTING_CLASS_PARAM); + code.addStatement("$T clazz = $T.resolveClassName($L, $L.getBeanClassLoader())", Class.class, + ClassUtils.class, IMPORTING_CLASS_PARAM, BEAN_FACTORY_PARAM); + code.addStatement("$T metadata = $T.introspect(clazz)", AnnotationMetadata.class, + AnnotationMetadata.class); + code.addStatement("new $T($L).registerBeanDefinitions(metadata, $L)", + ImportTestcontainersRegistrar.class, ENVIRONMENT_PARAM, BEAN_FACTORY_PARAM); + }); + } + + } + + } + } diff --git a/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/context/TestcontainerFieldBeanDefinition.java b/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/context/TestcontainerFieldBeanDefinition.java index cb181bab9b7c..43ced1121f6c 100644 --- a/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/context/TestcontainerFieldBeanDefinition.java +++ b/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/context/TestcontainerFieldBeanDefinition.java @@ -18,26 +18,13 @@ import java.lang.reflect.Field; -import javax.lang.model.element.Modifier; - import org.testcontainers.containers.Container; -import org.springframework.aot.generate.AccessControl; -import org.springframework.aot.generate.GenerationContext; -import org.springframework.beans.factory.aot.BeanRegistrationAotContribution; -import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor; -import org.springframework.beans.factory.aot.BeanRegistrationCode; -import org.springframework.beans.factory.aot.BeanRegistrationCodeFragments; -import org.springframework.beans.factory.aot.BeanRegistrationCodeFragmentsDecorator; +import org.springframework.beans.factory.aot.BeanRegistrationExcludeFilter; import org.springframework.beans.factory.support.RegisteredBean; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.boot.testcontainers.beans.TestcontainerBeanDefinition; import org.springframework.core.annotation.MergedAnnotations; -import org.springframework.javapoet.ClassName; -import org.springframework.javapoet.CodeBlock; -import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; -import org.springframework.util.ReflectionUtils; /** * {@link RootBeanDefinition} used for testcontainer bean definitions. @@ -70,87 +57,15 @@ public MergedAnnotations getAnnotations() { } /** - * {@link BeanRegistrationAotProcessor} that replaces InstanceSupplier of - * {@link Container} by either direct field usage or a reflection equivalent. - *

- * If the field is private, the reflection will be used; otherwise, direct access to - * the field will be used. - * + * {@link BeanRegistrationExcludeFilter} to exclude + * {@link TestcontainerFieldBeanDefinition} from AOT bean registrations. */ - static class TestcontainersBeanRegistrationAotProcessor implements BeanRegistrationAotProcessor { + static class TestcontainerBeanRegistrationExcludeFilter implements BeanRegistrationExcludeFilter { @Override - public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) { - RootBeanDefinition bd = registeredBean.getMergedBeanDefinition(); - String attributeName = TestcontainerFieldBeanDefinition.class.getName(); - Object field = bd.getAttribute(attributeName); - if (field != null) { - Assert.isInstanceOf(Field.class, field, "BeanDefinition attribute '" + attributeName - + "' value must be a type of '" + Field.class + "'"); - return BeanRegistrationAotContribution.withCustomCodeFragments( - (codeFragments) -> new AotContribution(codeFragments, registeredBean, ((Field) field))); - } - return null; - } - - private static final class AotContribution extends BeanRegistrationCodeFragmentsDecorator { - - private final RegisteredBean registeredBean; - - private final Field field; - - private AotContribution(BeanRegistrationCodeFragments delegate, RegisteredBean registeredBean, - Field field) { - super(delegate); - this.registeredBean = registeredBean; - this.field = field; - } - - @Override - public ClassName getTarget(RegisteredBean registeredBean) { - return ClassName.get(this.field.getDeclaringClass()); - } - - @Override - public CodeBlock generateInstanceSupplierCode(GenerationContext generationContext, - BeanRegistrationCode beanRegistrationCode, boolean allowDirectSupplierShortcut) { - - if (isFieldAccessible(beanRegistrationCode, this.field)) { - return CodeBlock.of("() -> $T.$L", this.field.getDeclaringClass(), this.field.getName()); - } - - generationContext.getRuntimeHints().reflection().registerField(this.field); - - return beanRegistrationCode.getMethods() - .add("getInstance", (method) -> method.addModifiers(Modifier.PRIVATE, Modifier.STATIC) - .addJavadoc("Get the bean instance for '$L'.", this.registeredBean.getBeanName()) - .returns(this.registeredBean.getBeanClass()) - .beginControlFlow("try") - .addStatement("$T clazz = $T.forName($S, $T.class.getClassLoader())", Class.class, - ClassUtils.class, ClassName.get(this.field.getDeclaringClass()), - beanRegistrationCode.getClassName()) - .addStatement("$T field = $T.findField(clazz, $S)", Field.class, ReflectionUtils.class, - this.field.getName()) - .addStatement("$T.notNull(field, $S)", Assert.class, - "Field '" + this.field.getName() + "' is not found") - .addStatement("$T.makeAccessible(field)", ReflectionUtils.class) - .addStatement("$T container = $T.getField(field, null)", Object.class, ReflectionUtils.class) - .addStatement("$T.notNull(container, $S)", Assert.class, - "Container field '" + this.field.getName() + "' must not have a null value") - .addStatement("return ($T) container", this.registeredBean.getBeanClass()) - .nextControlFlow("catch ($T ex)", ClassNotFoundException.class) - .addStatement("throw new $T(ex)", RuntimeException.class) - .endControlFlow()) - .toMethodReference() - .toCodeBlock(); - } - - private static boolean isFieldAccessible(BeanRegistrationCode beanRegistrationCode, Field field) { - ClassName className = beanRegistrationCode.getClassName(); - return AccessControl.forClass(field.getDeclaringClass()).isAccessibleFrom(className) - && AccessControl.forMember(field).isAccessibleFrom(className); - } - + public boolean isExcludedFromAotProcessing(RegisteredBean registeredBean) { + return registeredBean.getMergedBeanDefinition() + .hasAttribute(TestcontainerFieldBeanDefinition.class.getName()); } } diff --git a/spring-boot-project/spring-boot-testcontainers/src/main/resources/META-INF/spring/aot.factories b/spring-boot-project/spring-boot-testcontainers/src/main/resources/META-INF/spring/aot.factories index 1fd859d34a6a..712bee2847ab 100644 --- a/spring-boot-project/spring-boot-testcontainers/src/main/resources/META-INF/spring/aot.factories +++ b/spring-boot-project/spring-boot-testcontainers/src/main/resources/META-INF/spring/aot.factories @@ -1,14 +1,11 @@ org.springframework.beans.factory.aot.BeanRegistrationExcludeFilter=\ -org.springframework.boot.testcontainers.service.connection.ConnectionDetailsRegistrar.ServiceConnectionBeanRegistrationExcludeFilter,\ +org.springframework.boot.testcontainers.context.ImportTestcontainersRegistrar.ImportTestcontainersMetadataBeanRegistrationExcludeFilter,\ +org.springframework.boot.testcontainers.context.TestcontainerFieldBeanDefinition.TestcontainerBeanRegistrationExcludeFilter,\ org.springframework.boot.testcontainers.properties.TestcontainersPropertySource.EventPublisherRegistrarBeanRegistrationExcludeFilter,\ -org.springframework.boot.testcontainers.context.DynamicPropertySourceMethodsImporter.DynamicPropertySourceMetadataBeanRegistrationExcludeFilter +org.springframework.boot.testcontainers.service.connection.ConnectionDetailsRegistrar.ServiceConnectionBeanRegistrationExcludeFilter org.springframework.aot.hint.RuntimeHintsRegistrar=\ org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory.ContainerConnectionDetailsFactoriesRuntimeHints -org.springframework.beans.factory.aot.BeanRegistrationAotProcessor=\ -org.springframework.boot.testcontainers.context.TestcontainerFieldBeanDefinition.TestcontainersBeanRegistrationAotProcessor - - org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor=\ -org.springframework.boot.testcontainers.context.DynamicPropertySourceMethodsImporter.DynamicPropertySourceBeanFactoryInitializationAotProcessor +org.springframework.boot.testcontainers.context.ImportTestcontainersRegistrar.ImportTestcontainersBeanFactoryInitializationAotProcessor