Testing AOT contributions using the TestCompiler requires a lot of setup, and I am not even sure it is possible to test AOT contributions outside of the Spring Framework at the moment.

Here is an example: https://github.com/spring-projects/spring-framework/blob/62d98685ce1cb39202879690334e2cc660f69204/spring-aop/src/test/java/org/springframework/aop/scope/ScopedProxyBeanRegistrationAotProcessorTests.java#L63-L80

  • TestBeanRegistrationsAotProcessor is an internal test fixture (empty class to make a protected class public)
  • MockBeanFactoryInitializationCode is defined in the test
  • testCompile is rather involved

Perhaps a JUnit extension would be useful?

Comment From: sbrannen

I am not even sure it is available outside of the Spring Framework at the moment.

spring-core-test is now published.

  • See #28558

Comment From: snicoll

I am aware of that.

Typo. I meant: "I am not sure testing AOT contributions is possible outside of the Spring Framework at the moment".

Comment From: snicoll

@philwebb I am looking at this and I am not sure how I could proceed. My first attempt is to write something that does the necessary setup to invoke a BeanRegistrationAotProcessor. The setup could be something along the lines of "discover what is available" or "use these configured processors".

To be able to do that. It looks like I need to be able to access BeanDefinitionMethodGeneratorFactory and then BeanDefinitionMethodGenerator so that I can invoke generateBeanDefinitionMethod. To do that, I'd need a BeanRegistrationsCode implementation (it isn't public).

Based on the MethodReference the extension could create a simple ApplicationContextInitializer that just uses this method. It feels to me that the extension could reuse whatever the production code does (some partial code in BeanRegistrationsAotContribution).

The extension wrapping TestCompiler and then invoking the generated code looks doable.

Comment From: snicoll

Another problem is that TestBeanRegistrationsAotProcessor is in testfixtures and in the same package as the class it extends from to have access to it. This creates a package split and things should be under the testfixture sub-package of the related module.

Comment From: snicoll

I've started some hacking (https://github.com/snicoll/spring-framework/commit/cd527552417cb0bb9258292eb7c176df4d1577d7) based on one test but I am hitting what seems to be a split package problem with the test compiler @philwebb:

Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @44e81672
    at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)
    at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
    at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:199)
    at java.base/java.lang.reflect.Method.setAccessible(Method.java:193)
    at org.springframework.cglib.core.ReflectUtils$1.run(ReflectUtils.java:61)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:569)
    at org.springframework.cglib.core.ReflectUtils.<clinit>(ReflectUtils.java:52)

Comment From: philwebb

Is it possible to add @CompileWithTargetClassAccess to the test? Another "fix" might be to add --add-opens=java.base/java.net=ALL-UNNAMED to the build. We did that recently with Spring Boot.

Comment From: snicoll

The problem remains, but I am not sure that trying to abstract this away is going to be any better. spring-core-test provides a fist good level. We can reconsider based on specific request.