Java to Native Code: it's so easy (uber jar)
GraalVM is now joining openjdk (archive), so it’s time to review how to compile java to native code, because it’s so easy!
1. Single File, dependencies in a über jar
Assuming you’ve already installed GraalVM, you have access to native-image
.
If you have external dependencies, the easiest is generate a "über jar", and
then asking native-image
to compile a static binary from it.
2. Example
Let’s try a simple cli program, depending on picocli (archive), a feature-rich library to write cli on the JVM:
import picocli.CommandLine;
import java.util.concurrent.Callable;
@CommandLine.Command(
name = "hello-cli",
mixinStandardHelpOptions = true,
version = "1.0",
description = "Prints a nice hello")
public class HelloCli implements Callable<Integer> {
@Override
public Integer call() {
System.out.println("Bien le bonjour, humain.");
return 0;
}
public static void main(String... args) {
int exitCode = new CommandLine(new HelloCli()).execute(args);
System.exit(exitCode);
}
}
Then, we need to generate the über jar, for example with maven-assembly-plugin
if you use a pom.xml
to describe your dependencies:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<archive>
<manifest>
<mainClass>
com.your.path.HelloCli
</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</execution>
</executions>
</plugin>
And then generate that jar:
mvn clean package
Finally, let’s compile our native executable:
native-image -jar ./target/hello-cli-1.0-SNAPSHOT-jar-with-dependencies.jar hello-cli
3. Result
This native executable is ready to be launched:
$ ./hello-cli -h
Usage: hello-cli [-hV]
Prints a nice hello
-h, --help Show this help message and exit.
-V, --version Print version information and exit.
$ ./hello-cli
Bien le bonjour, humain.
This was so easy!