We are pleased to announce the release of the new official GraalVM Native Image Gradle and Maven plugins. The plugins aim to make GraalVM Native Image a first-class citizen in the JVM ecosystem: it makes building, testing, and running Java applications as native executables a breeze. The key new feature is the out-of-the-box support for native JUnit 5 testing
The native JUnit support allows libraries in the JVM ecosystem to run their test suites via GraalVM Native Image. With integrated testing, library configuration should be always up to date and ready for the end user. We believe that this is the biggest step towards making the Java ecosystem native-ready.
Complete examples are available here.
We’ve made it: testing Java code with JUnit 5 behaves exactly the same* in native execution as with the JVM.
To make this work, we implemented a custom junit-platform-native
feature that logs tests that are discovered during the previous execution of the standard JVM test
task and registers them for native compilation and reflection.
Based on this information, special test executable that contains all the tests (and their metadata) is built, and then invoked when using the corresponding build-tool task.
Collection of metadata imposes the dependency to the JVM test
task execution.
The downside of this is increased testing time, but it also provides a suitable entry point for users to enable native-image-agent
invocation that can be used to generate missing reflection configuration for the project.
Note that the agent invocation is independent of the test-metadata collection — the test metadata is always collected.
In the future we intend to work on removing the dependency on the JVM
test
execution. For this, we need modifications in the testing frameworks that will allow metadata collection without the execution of individual tests (a.k.a., dry-run support).
* Given proper configuration, and given that the project under test doesn’t include native-specific code (e.g., build-time initialization, substitutions, and plugins).
Adding native-gradle-plugin
to an existing Gradle project is as simple as including following to the plugins
section of the build.gradle
plugins {
id 'org.graalvm.buildtools.native' version "0.9.0" // or a newer version
}
as well as adding the following to the settings.gradle
:
pluginManagement {
repositories {
mavenCentral()
gradlePluginPortal()
}
}
(this step will be redundant once this plugin is published to the Gradle Plugin Portal).
After that, we can configure the image build by using a graalvmNative
configuration block:
graalvmNative {
binaries {
main {
imageName = "my-app"
mainClass = "org.test.Main"
verbose = true
fallback = false
}
}
}
The plugin then adds nativeCompile
and nativeRun
tasks that respectively creates a native executable and runs the main class (as one might expect ☺).
If the reflection configuration is necessary for the Native Image building, this plugin also provides a simple option that activates the native-image-agent
without any additional user setup.
More information (and Kotlin configuration syntax) is available in the documentation.
User can start Native Image testing by invoking the nativeTest
task (with the ability to add additional native-image
configuration using a nativeTest
configuration block).
$ ./gradlew nativeTest
> Task :nativeTest
JUnit Platform on Native Image - report
----------------------------------------
org.graalvm.buildtools.example.App2Test > appHasAGreeting() SUCCESSFUL
org.graalvm.buildtools.example.AppTest > appHasAGreeting() SUCCESSFUL
Test run finished after 3 ms
[ 3 containers found ]
[ 0 containers skipped ]
[ 3 containers started ]
[ 0 containers aborted ]
[ 3 containers successful ]
[ 0 containers failed ]
[ 2 tests found ]
[ 0 tests skipped ]
[ 2 tests started ]
[ 0 tests aborted ]
[ 2 tests successful ]
[ 0 tests failed ]
BUILD SUCCESSFUL in 771ms
5 actionable tasks: 1 executed, 4 up-to-date
Note that the native testing depends on running the standard
test
task in the JVM mode beforehand.
We are releasing our existing plugin under the new maven coordinates — org.graalvm.buildtools:native-maven-plugin
.
This change was motivated by our intention to move faster with the plugin development by decoupling it from the GraalVM release cycle.
Users of our existing native-image-maven-plugin
only need to change the plugin’s groupId
, artifactId
and version
in their pom.xml
, as the new plugin is backwards compatible with the old one.
Versioning of the new plugin will start at 0.9.0
.
Adding our new plugin to the existing Maven project requires adding the following to the pom.xml
:
<profiles>
<profile>
<id>native</id>
<build>
<plugins>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
<version>0.9.0</version> <!-- or newer version -->
<executions>
<execution>
<id>test-native</id>
<goals>
<goal>test</goal>
</goals>
<phase>test</phase>
</execution>
<execution>
<id>build-native</id>
<goals>
<goal>compile-no-fork</goal>
</goals>
<phase>package</phase>
</execution>
</executions>
<configuration>
<imageName>my-app</imageName>
<mainClass>org.test.Main</mainClass>
<buildArgs>
--no-fallback
--verbose
</buildArgs>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
After that, the user can build native images by running:
mvn -Pnative -DskipTests package
The user can start Native Image testing by running:
mvn -Pnative test
Note that the native testing depends on running the standard test task in the JVM mode beforehand.
Documentation and more configuration options are available here.
The next step is creating a standardized repository with configuration that would be automatically added for legacy libraries. This should make the development for Native Image feels more frictionless even for libraries that don’t support it yet. We intend to follow up with patches and _PR_s for original libraries, working closely with the community in order to bring first party support to the most of the ecosystem.
Our testing support was developed in collaboration with JUnit, Micronaut, and Spring teams. Many thanks to Sam Brannen, Graeme Rocher, and Sébastien Deleuze for their contributions and advice. Moving forward, our new plugins are already landing in Spring Native 0.10.0, and hopefully soon many more projects will follow.
We are looking forwards to hearing about your experiences and/or potential issues. Contributions are also very welcome.
The project repository is available at github.com/graalvm/native-build-tools.
All projects mentioned here are released under the Universal Permissive License.