How to Prepare Native Image Configuration Files in The Most Complete Format?

http://www.peoplefinderdirect.co.uk/

GraalVM is a high-performance runtime that supports additional programming languages and execution modes but the main thing that makes it popular is a technology to ahead-of-time compile Java code to a standalone executable called native image.

Why are Native Image Configuration Files Needed?

As every rose has it’s a thorn, although the native image is an exciting technology, it has some limitations due to the nature of ahead-of-time compilation. The native image builder statically analyzes all classes of the application and their dependencies to determine which classes and methods are reachable during the application execution. This is an optimization process and it's executed according to the closed-world assumption that all application classes need to be known at native image generation time so that the static analysis can process them.

On the other hand, in the open-world approach, Java developers can look up classes, methods, and fields with their names and access/invoke them by Java Reflection. At this point, a clear conflict arises between the closed-world assumption and the open-world approach. However, the native image builder tries to resolve the target elements in the static analysis time mentioned above to detects calls to the Reflection API but in all cases, it cannot be successful.

This is the reason GraalVM needs configuration files to use at native image build time for features that follow the open-world approach, such as Dynamic Class Loading, Dynamic Proxy, Reflection, etc.

Tracing Agent

It could be so easy to prepare the configuration files from scratch for the above-mentioned features when we do not use 3rd party libraries in our application. However, it is an undeniable fact that we needed and used 3rd party libraries widely in real-world applications.

Let’s think about the difficulty of manual providing configuration files from scratch when using 3rd party libraries with an example. Suppose we have an application that consumes a Kafka topic. The application uses explicitly some classes of the Kafka client depending on record types due to Deserializing need and we know these classes must be defined in the configuration file for the native image generation process. However, other classes can also be accessed via reflection by the client under the hood for consumption and the same need. It is not easy to detect these classes always that are used implicitly from our point of view and this difficulty makes manual preparing the configuration troublesome and error-prone when you want to generate a native image from the application.

Fortunately, thanks to the tracing agent, preparing these configuration files becomes easier and more convenient. The agent tracks all usages of dynamic features of execution on a regular Java VM and creates configuration files in the directory you defined at the command-line.

How Can I Use?

You can enable the agent on the command line of the GraalVM java command.

$GRAAL_HOME/bin/java -agentlib:native-image-agent=config-output-dir=/path/to/config-dir/ -jar /path/to/jar-dir/

Notice that, -agentlib option must be specified before the -jar option(similarly before the class name) and any other application parameters in the java command line.

During execution, the agent intercepts all calls related to the limitations mentioned earlier, and after the JVM process terminates, it generates the configuration files based on the calls it interrupts in the specified output directory. You will have the following files after execution.

  • jni-config.json
  • reflect-config.json
  • proxy-config.json
  • resource-config.json

These files are standalone configuration files in JSON format which contain all intercepted dynamic accesses. For our hypothetical example mentioned above, the contents of the reflect-config.json file would be as follows.

{
"name":"org.apache.kafka.clients.consumer.RangeAssignor",
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name":"org.apache.kafka.common.serialization.StringDeserializer"
},
{
"name":"org.apache.kafka.common.utils.AppInfoParser$AppInfo",
"allPublicConstructors":true
},
{
"name":"org.apache.kafka.common.utils.AppInfoParser$AppInfoMBean",
"allPublicMethods":true
}

Lines unrelated to our 3rd party library have been omitted to reduce the length of the file.

In most cases, to get the most better coverage of dynamic accesses, you want to run the target application more than once with different inputs to trigger separate execution paths. In this case, you can use config-merge-dir option which augments the configuration files by adding the intercepted accesses to existing files.

Manually Inspection The Configuration Files

The developers of GraalVM suggest manual inspection of the generated configuration files because the agent observes only code that was executed. Depending on your usage scenario, it's always possible was missed some elements in the resulting configuration files. In addition, the agent isn't perfect, so it can generate non-compatible entries with the runtime environment hence you shouldn't hesitate to make changes manually on the files when the need arises.

Conclusion

GraalVM executes the native image build process according to the closed-world assumption that means all application classes need to be known at native image generation time. Hence, it needs configuration files to use at native image build time for supporting some features that follow the open-world approach, such as Dynamic Class Loading, Dynamic Proxy, Reflection, etc.

It is difficult and error-prone to manual provide configuration files from scratch when using 3rd party libraries. The tracing agent is a facilitating solution at this point. It intercepts all dynamic calls and then generates the configuration files based on the calls. Because the agent observes only code that was executed, it is most important to run the target application more than once with different inputs to trigger separate execution paths for getting better coverage of dynamic accesses.

References

GraalVM Documentation

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Hüseyin Akdoğan

Hüseyin Akdoğan

Expert Software Engineer and Consultant at Patika Global Technology