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 testtestCompile
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.