diff --git a/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/ConnectionDetailsRegistrar.java b/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/ConnectionDetailsRegistrar.java index 90c0580926..318ef6a5f9 100644 --- a/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/ConnectionDetailsRegistrar.java +++ b/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/ConnectionDetailsRegistrar.java @@ -28,7 +28,9 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.ListableBeanFactory; +import org.springframework.beans.factory.aot.BeanRegistrationExcludeFilter; import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.RegisteredBean; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails; import org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactories; @@ -102,7 +104,9 @@ class ConnectionDetailsRegistrar { Class beanType = (Class) connectionDetails.getClass(); Supplier beanSupplier = () -> (T) connectionDetails; logger.debug(LogMessage.of(() -> "Registering '%s' for %s".formatted(beanName, source))); - registry.registerBeanDefinition(beanName, new RootBeanDefinition(beanType, beanSupplier)); + RootBeanDefinition beanDefinition = new RootBeanDefinition(beanType, beanSupplier); + beanDefinition.setAttribute(ServiceConnection.class.getName(), true); + registry.registerBeanDefinition(beanName, beanDefinition); } private String getBeanName(ContainerConnectionSource source, ConnectionDetails connectionDetails) { @@ -113,4 +117,13 @@ class ConnectionDetailsRegistrar { return StringUtils.uncapitalize(parts.stream().map(StringUtils::capitalize).collect(Collectors.joining())); } + class ServiceConnectionBeanRegistrationExcludeFilter implements BeanRegistrationExcludeFilter { + + @Override + public boolean isExcludedFromAotProcessing(RegisteredBean registeredBean) { + return registeredBean.getMergedBeanDefinition().getAttribute(ServiceConnection.class.getName()) != null; + } + + } + } 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 new file mode 100644 index 0000000000..52cbdbe6b1 --- /dev/null +++ b/spring-boot-project/spring-boot-testcontainers/src/main/resources/META-INF/spring/aot.factories @@ -0,0 +1,2 @@ +org.springframework.beans.factory.aot.BeanRegistrationExcludeFilter=\ +org.springframework.boot.testcontainers.service.connection.ConnectionDetailsRegistrar.ServiceConnectionBeanRegistrationExcludeFilter \ No newline at end of file diff --git a/spring-boot-project/spring-boot-testcontainers/src/test/java/org/springframework/boot/testcontainers/service/connection/ServiceConnectionAutoConfigurationTests.java b/spring-boot-project/spring-boot-testcontainers/src/test/java/org/springframework/boot/testcontainers/service/connection/ServiceConnectionAutoConfigurationTests.java index a55163bd1e..6e7fefc653 100644 --- a/spring-boot-project/spring-boot-testcontainers/src/test/java/org/springframework/boot/testcontainers/service/connection/ServiceConnectionAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-testcontainers/src/test/java/org/springframework/boot/testcontainers/service/connection/ServiceConnectionAutoConfigurationTests.java @@ -21,6 +21,7 @@ import java.util.Set; import org.junit.jupiter.api.Test; import org.mockito.Mockito; +import org.springframework.aot.test.generate.TestGenerationContext; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.beans.factory.support.RootBeanDefinition; @@ -36,11 +37,13 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; +import org.springframework.context.aot.ApplicationContextAotGenerator; import org.springframework.core.annotation.MergedAnnotation; import org.springframework.core.annotation.MergedAnnotations; import org.springframework.core.type.AnnotationMetadata; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatNoException; import static org.mockito.Mockito.mock; /** @@ -101,6 +104,17 @@ class ServiceConnectionAutoConfigurationTests { } } + @Test + void serviceConnectionBeansDoNotCauseAotProcessingToFail() { + try (AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext()) { + applicationContext.register(WithNoExtraAutoConfiguration.class, ContainerConfiguration.class); + new TestcontainersLifecycleApplicationContextInitializer().initialize(applicationContext); + TestGenerationContext generationContext = new TestGenerationContext(); + assertThatNoException().isThrownBy(() -> new ApplicationContextAotGenerator() + .processAheadOfTime(applicationContext, generationContext)); + } + } + @Configuration(proxyBeanMethods = false) @ImportAutoConfiguration(ServiceConnectionAutoConfiguration.class) static class WithNoExtraAutoConfiguration {