-
Notifications
You must be signed in to change notification settings - Fork 40.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
@ImportTestcontainers doesn't work with AOT #42891
base: 3.2.x
Are you sure you want to change the base?
Conversation
86d62e3
to
2b1535f
Compare
Another idea that came to my mind is to replace Similar to |
91e3273
to
cd63de3
Compare
Unfortunately, handling the bean instance supplier for container fields only addresses |
008de18
to
65e3548
Compare
Initially, my idea was to generate code similar to public class TestA__TestContext001_ApplicationContextInitializer implements ApplicationContextInitializer<GenericApplicationContext> {
@Override
public void initialize(GenericApplicationContext applicationContext) {
DefaultListableBeanFactory beanFactory = applicationContext.getDefaultListableBeanFactory();
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
new TestA__TestContext001_BeanFactoryRegistrations().registerBeanDefinitions(beanFactory);
new TestA__TestContext001_BeanFactoryRegistrations().registerAliases(beanFactory);
ImportTestcontainersRegistrar__TestContext001_ImportTestcontainers.registerBeanDefinitions(applicationContext.getEnvironment(), beanFactory);
}
}
@Generated
public class ImportTestcontainersRegistrar__TestContext001_ImportTestcontainers {
/**
* Register bean definitions for 'ImportTestcontainers'
*/
public static void registerBeanDefinitions(ConfigurableEnvironment environment,
DefaultListableBeanFactory beanFactory) {
Set<Class<?>> definitionClasses = new LinkedHashSet<>();
definitionClasses.add(ClassUtils.resolveClassName("task.graalmaven.TestcontainersConfiguration", beanFactory.getBeanClassLoader()));
definitionClasses.add(ClassUtils.resolveClassName("task.graalmaven.GraalmavenApplicationTests", beanFactory.getBeanClassLoader()));
new ImportTestcontainersRegistrar(environment).registerBeanDefinitions(beanFactory, definitionClasses.toArray(new Class<?>[0]));
}
} If it is wrong, the previous af6ce70 commit generates bean definitions and @Generated
public class TestA__TestContext001_ApplicationContextInitializer implements ApplicationContextInitializer<GenericApplicationContext> {
@Override
public void initialize(GenericApplicationContext applicationContext) {
DefaultListableBeanFactory beanFactory = applicationContext.getDefaultListableBeanFactory();
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
new TestA__TestContext001_BeanFactoryRegistrations().registerBeanDefinitions(beanFactory);
new TestA__TestContext001_BeanFactoryRegistrations().registerAliases(beanFactory);
registerDynamicPropertySources(applicationContext.getEnvironment(), beanFactory);
}
/**
* Registers {@code @DynamicPropertySource} properties
*/
private static void registerDynamicPropertySources(ConfigurableEnvironment environment,
DefaultListableBeanFactory beanFactory) {
DynamicPropertyRegistry dynamicPropertyRegistry = TestcontainersPropertySource.attach(environment, beanFactory);
GraalmavenApplicationTests__TestContext001_DynamicPropertySource.registerDynamicPropertySource(dynamicPropertyRegistry);
}
}
@Generated
public class GraalmavenApplicationTests__TestContext001_DynamicPropertySource {
/**
* Register {@code @DynamicPropertySource} for method 'GraalmavenApplicationTests.mongoProperties'
*/
private static void mongoProperties(DynamicPropertyRegistry dynamicPropertyRegistry) {
Class<?> clazz = ClassUtils.resolveClassName("task.graalmaven.GraalmavenApplicationTests", GraalmavenApplicationTests__TestContext001_DynamicPropertySource.class.getClassLoader());
ReflectionTestUtils.invokeMethod(clazz, "mongoProperties", dynamicPropertyRegistry);
}
/**
* Registers {@code @DynamicPropertySource} properties for class 'GraalmavenApplicationTests'
*/
public static void registerDynamicPropertySource(
DynamicPropertyRegistry dynamicPropertyRegistry) {
GraalmavenApplicationTests__TestContext001_DynamicPropertySource.mongoProperties(dynamicPropertyRegistry);
}
}
@Generated
public class GraalmavenApplicationTests__TestContext001_BeanDefinitions {
/**
* Get the bean instance for 'importTestContainer.task.graalmaven.GraalmavenApplicationTests.mongoDbContainer'.
*/
private static MongoDBContainer getMongoDbContainerInstance() {
Class<?> clazz = ClassUtils.resolveClassName("task.graalmaven.GraalmavenApplicationTests",
GraalmavenApplicationTests__TestContext001_BeanDefinitions.class.getClassLoader());
Field field = ReflectionUtils.findField(clazz, "mongoDbContainer");
Assert.notNull(field, "Field 'mongoDbContainer' is not found");
ReflectionUtils.makeAccessible(field);
Object container = ReflectionUtils.getField(field, null);
Assert.notNull(container, "Container field 'mongoDbContainer' must not have a null value");
return (MongoDBContainer) container;
}
/**
* Get the bean definition for 'mongoDbContainer'.
*/
public static BeanDefinition getMongoDbContainerBeanDefinition() {
RootBeanDefinition beanDefinition = new RootBeanDefinition(MongoDBContainer.class);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
beanDefinition.setInstanceSupplier(
GraalmavenApplicationTests__TestContext001_BeanDefinitions::getMongoDbContainerInstance);
return beanDefinition;
}
} |
@philwebb |
aeb137a
to
7c38b50
Compare
…lier of 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 DynamicPropertySourceBeanFactoryInitializationAotProcessor that generates methods for each annotated @DynamicPropertySource method
…hat collects all importing classes and then generates an initializer method that invokes ImportTestcontainersRegistrar.registerBeanDefinitions(...) for those classes
#42875
Since Bean's InstanceSupplier cannot be used during the AOT process, I added
BeanRegistrationAotProcessor
to replace it.If a container's field is inaccessible, the generated code will be:
If a container's field is accessible, the generated code will be:
An alternative way is
FactoryBean
instead ofInstanceSupplier
.The target branch is 3.2.x