Gradle and Maven Plugins for Native Image with Initial JUnit 5 Testing Support

Lazar Mitrović
graalvm
Published in
4 min readJun 14, 2021

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.

Native Testing: The Way You Are Used to It

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 from 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).

For more information users should consult the plugin documentation for Maven or Gradle.

* Given proper configuration, and given that the project under test doesn’t include native-specific code (e.g., build-time initialization, substitutions, and plugins).

Gradle Plugin

Adding native-gradle-plugin to an existing Gradle project is as simple as including following to the plugins section of the build.gradle

as well as adding the following to the settings.gradle:

(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 nativeBuild configuration block:

The plugin then adds nativeBuild and nativeRun tasks that build and run 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.

To help ease the community transition, at the moment we support a subset of the configuration syntax and aliased task names from the most popular unofficial GraalVM Gradle plugins (io.micronaut.application and com.palantir.graal). Note that this behavior might eventually be deprecated.

Testing in Gradle

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).

Note that the native testing depends on running the standard test task in the JVM mode beforehand.

Maven Plugin

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 thepom.xml:

After that, the user can build native images by running:

mvn -Pnative -DskipTests package

Testing in Maven

The user can start Native Image testing by running:

mvn -Pnative test

Maven plugin currently requires an extra step in order to enable said listener: The user needs to add a dependency to org.graalvm.buildtools:junit-platform-native in their pom.xml. This step will not be necessary once JUnit 5.8 lands.

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.

Future Goals

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 PRs for original libraries, working closely with the community in order to bring first party support to the most of the ecosystem.

Built with Love Through Collaboration

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.

--

--