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:

@Generated
public class GraalmavenApplicationTests__TestContext001_BeanDefinitions {

    /**
     * Get the bean instance for 'importTestContainer.task.graalmaven.GraalmavenApplicationTests.mongoDbContainer'.
     */
    private static MongoDBContainer getMongoDbContainerInstance() {
        try {
            Class<?> clazz = ClassUtils.forName("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;
        } catch (ClassNotFoundException ex) {
            throw new RuntimeException(ex);
        }
    }

    /**
     * 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;
    }

}

If a container's field is accessible, the generated code will be:

@Generated
public class GraalmavenApplicationTests__TestContext001_BeanDefinitions {
  /**
   * Get the bean definition for 'mongoDbContainer'.
   */
  public static BeanDefinition getMongoDbContainerBeanDefinition() {
    RootBeanDefinition beanDefinition = new RootBeanDefinition(MyContainer.class);
    beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    beanDefinition.setInstanceSupplier(() -> GraalmavenApplicationTests.mongoDbContainer);
    return beanDefinition;
  }
}

An alternative way is FactoryBean instead of InstanceSupplier.

The target branch is 3.2.x

Comment From: nosan

Unfortunately, handling the bean instance supplier for container fields only addresses half of the issue. The more problematic part involves handling @DynamicPropertySource methods. These @DynamicPropertySource methods need to be generated and invoked within the AOT environment. To achieve this, I introduced DynamicPropertySourceBeanFactoryInitializationAotProcessor

Comment From: nosan

@philwebb Could I kindly ask you to do a quick review of this PR, and let me know if I'm in the right direction?

Comment From: philwebb

Sorry for the delay @nosan, I haven't had the chance to look in detail at this one yet.

Comment From: nosan

@philwebb No worries! I completely understand that you’ve been focusing on higher-priority tasks.