I'm trying to create a GraalVM native image using the maven plugin but having some issues.
Here the config for the maven plugin
I'm using GraalVM JDK (installed through Sdkman):
$ java -version
openjdk version "16.0.1" 2021-04-20
OpenJDK Runtime Environment GraalVM CE 21.1.0 (build 16.0.1+9-jvmci-21.1-b05)
OpenJDK 64-Bit Server VM GraalVM CE 21.1.0 (build 16.0.1+9-jvmci-21.1-b05, mixed mode, sharing)
I have a done simple main class like:
package it.r;
public class Main {
public static void main(String[] args) {
System.out.println("********");
System.out.println(Main.class.getConstructors().length);
System.out.println("********");
}
}
When executing it using mvn exec:java -Dexec.mainClass=it.r.Main
I get as a result:
********
1
********
But when doing mvn package
and then executing the created executable, I have as result:
********
0
********
Why is this happening?
Here the git repo to reproduce
This issue seems to impact Jackson deserialization, as in another example I have an error from jackson that cannot deserialize a yaml file because it can't find constructors for my class.
When GraalVM native image builds your application into a native binary it statically analyzes your application.
The analysis is static, so several dynamic features your application might use require explicit configuration, for example:
classloader.getResource()
)This explicit configuration is provided as json configuration files, for example,
You can provide the config files manually, but you can also run your application using a javaagent which will record usages of features requiring configuration.
In a nutshell, you run your application like this:
java -agentlib:native-image-agent=config-output-dir=/path/to/config-dir/
and exercise the code paths that use the code you want to be configured. This is important because the tracing agent can only record the config for the code it actually saw running.
Then the output directory will contain a json file, for example looking like this:
[
{
"name":"StringCapitalizer",
"methods":[{"name":"capitalize","parameterTypes":["java.lang.String"] }]
},
{
"name":"StringReverser",
"methods":[{"name":"reverse","parameterTypes":["java.lang.String"] }]
}
This file lists the classes that need to be included into the analysis and the binary result and their members that need to be accessed. It’s fairly straightforward but a bit tedious to create manually that’s why the agent approach is preferred.
There’s also a programmatic way to configure classes and members be registered for reflection, but using it means you need to include a dependency on the GraalVM code into your app.