This can be reproduced using https://github.com/snicoll/demo-aot-native

A call to ./gradlew nativeCompile works as expected.

However, calling ./gradlew nativeTest leads to:

> Task :nativeTestCompile
[native-image-plugin] Toolchain detection is disabled, will use GraalVM from /Users/snicoll/.sdkman/candidates/java/graalvm.
[native-image-plugin] Using executable path: /Users/snicoll/.sdkman/candidates/java/graalvm/bin/native-image
========================================================================================================================
GraalVM Native Image: Generating 'demo-aot-native-tests' (executable)...
========================================================================================================================
Warning: Could not resolve com.example.demo.DemoAotNativeApplication$$SpringCGLIB$$0 for reflection configuration. Reason: java.lang.ClassNotFoundException: com.example.demo.DemoAotNativeApplication$$SpringCGLIB$$0.

The com.example.demo.DemoAotNativeApplication$$SpringCGLIB$$0 class is generated in the expected directory:

$ tree build/generated/aotTestClasses
build/generated/aotTestClasses
└── com
    └── example
        └── demo
            └── DemoAotNativeApplication$$SpringCGLIB$$0.class

3 directories, 1 file

Comment From: wilkinsona

It isn't the cause of this problem, but why is generation of test classes processing main code? If you run processAot and processAotTest, you'll see that DemoAotNativeApplication$$SpringCGLIB$$0.class has been generated twice:

build/generated
├── aotClasses
│   └── com
│       └── example
│           └── demo
│               └── DemoAotNativeApplication$$SpringCGLIB$$0.class
…
├── aotTestClasses
│   └── com
│       └── example
│           └── demo
│               └── DemoAotNativeApplication$$SpringCGLIB$$0.class

This appears to be specific to class generation as I don't see the same duplication in the generated sources. The two classes are identical, but having two copies doesn't feel right. For tests, I think we should use the one from aotClasses as it's the one that should be used at runtime. The ideal would be for only one to be generated.