Note that the AOT process has several limitations beyond reflection. Depending on how the underlying code was written, it might be subject to more than just that. In somes cases, there are different ways to fix that. Those will be covered in a future post: let’s focus on reflection proper for now.

In Java, some of the underlying code relies more or less on runtime-based reflection. Unfortunately, that means that at compile-time, SubstrateVM will remove code that it deems is not required, though it is. This can be configured, though, via JSON files. Given the amount of calls relying on reflection, manual configuration is a daunting task.

SubstrateVM offers a better alternative, though: it provides a Java agent that can set on the command-line of the running controller. This agent intercepts every reflection call made inside the controller application, and records it in a dedicated reflect-config.json file. That first requires to build a container image with this agent, and to access every nook and cranny of the containerized app. Leave no stone unturned!

On a later stage, this file (along with other similar ones) can be fed to the compilation process, so that the code accessed through reflection is kept. One way to feed them is through the command-line. Another one is to package them inside the JAR in a dedicated folder: this allows libraries' providers to offer AOT-compatible JARs and should be the preferred way.