Using JDK21 Preview Features and/or incubator classes

Sometimes you want to play around with those new fancy features of JDK21 (or even newer JDK's) like preview features and maybe some classes from the incubator.

So how can you configure your Maven build to support such a play lesson? It's easier than you think. Let's start the configuration. My assumption is that you would like to play around with a preview features of JDK21 for example String Templates (JEP430). I just selected this JEP for demonstration. You can select whatever JEP in preview.

The first thing is to know that you have to activate the preview features via:

1<plugin>
2  <groupId>org.apache.maven.plugins</groupId>
3  <artifactId>maven-compiler-plugin</artifactId>
4  <configuration>
5    <enablePreview>true</enablePreview>
6  </configuration>
7</plugin>

The configuration enablePreview exists since version 3.10.1 of the Maven Compiler Plugin. So in general I recommend to use the most recent versions of the plugins otherwise it might happen that some configuration options or alike might not exist at all or special things for newer JDK versions.

This should be done in general in the pluginManagement section of your pom.xml file.

So now you are able to use this new feature in your test code (you could use it in your production code as well if you prefer that):

 1package com.soebes.jdk21;
 2
 3import org.junit.jupiter.api.Test;
 4
 5import static java.lang.StringTemplate.STR;
 6import static org.assertj.core.api.Assertions.assertThat;
 7
 8class TemplateTest {
 9  @Test
10  void name() {
11    String name = "Jon";
12    String info = STR."My name is \{name}";
13    assertThat(info).isEqualTo("My name is Jon");
14  }
15
16}

Ok so far so good, but wait, before you can run this test you have to do a bit more. We need to change the configuration to run the test with the support of preview feature. This is required to give the JVM the option --enable-preview which is used during the execution of the tests. This has to be done like the following:

1<plugin>
2  <groupId>org.apache.maven.plugins</groupId>
3  <artifactId>maven-surefire-plugin</artifactId>
4  <configuration>
5    <argLine>
6      --enable-preview
7    </argLine>
8  </configuration>
9</plugin>

As I mentioned before, I strongly recommend to use the most recent versions of the plugins.

One important thing to mention. If you run those tests or the whole build you will get some WARNINGs like the following:

1[INFO] --- compiler:3.11.0:testCompile (default-testCompile) @ jdk21 ---
2[INFO] Changes detected - recompiling the module! :dependency
3[INFO] Compiling 5 source files with javac [release 21] to target/test-classes
4[WARNING] ../jdk21/src/test/java/com/soebes/jdk21/TemplateTest.java:[12,23] string templates are a preview feature and may be removed in a future release.
5[WARNING] ../jdk21/src/test/java/com/soebes/jdk21/TemplateTest.java:[12,23] string templates are a preview feature and may be removed in a future release.
6[WARNING] ../jdk21/src/test/java/com/soebes/jdk21/TemplateTest.java:[5,24] java.lang.StringTemplate is a preview API and may be removed in a future release.
7[INFO] 

Those WARNINGs would have been emitted during the production code compilation if you used such feature in the production already. This makes it clear that you are using such preview features.

And an extremely important hint:

Never deploy such code which uses preview features anywhere. Not in your company repository manger nor into central repository

The StringTemplate class is marked as a preview feature independent that it is the package java.lang:

1@PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES)
2public interface StringTemplate {
3  ...
4
5}

So another nice thing would be to use a class from the incubator like the Vector API? Ok. What do we need to do? The first thing is to enhance our previous configuration with the --add-modules jdk.incubator.vector information like the following:

 1<plugin>
 2  <groupId>org.apache.maven.plugins</groupId>
 3  <artifactId>maven-compiler-plugin</artifactId>
 4  <configuration>
 5    <enablePreview>true</enablePreview>
 6    <compilerArgs>
 7      <arg>--add-modules</arg>
 8      <arg>jdk.incubator.vector</arg>
 9    </compilerArgs>
10  </configuration>
11</plugin>

And of course you have to add the same to add to the maven-surefire-plugin configuration to activate the jdk.incubator.vector module in your tests as well. This means the configuration for maven-surefire-plugin should look like the following:

 1<plugin>
 2  <groupId>org.apache.maven.plugins</groupId>
 3  <artifactId>maven-surefire-plugin</artifactId>
 4  <configuration>
 5    <argLine>
 6      --enable-preview
 7      --add-modules jdk.incubator.vector
 8    </argLine>
 9  </configuration>
10</plugin>

This results in WARNING as before as the following:

 1..
 2[INFO] --- compiler:3.11.0:compile (default-compile) @ jdk21 ---
 3[INFO] Changes detected - recompiling the module! :source
 4[INFO] Compiling 2 source files with javac [release 21] to target/classes
 5[WARNING] using incubating module(s): jdk.incubator.vector
 6[INFO] 
 7[INFO] --- resources:3.3.1:testResources (default-testResources) @ jdk21 ---
 8[INFO] skip non existing resourceDirectory ../jdk21/src/test/resources
 9[INFO] skip non existing resourceDirectory ../jdk21/src/test/resources-filtered
10[INFO] 
11[INFO] --- compiler:3.11.0:testCompile (default-testCompile) @ jdk21 ---
12[INFO] Changes detected - recompiling the module! :dependency
13[INFO] Compiling 5 source files with javac [release 21] to target/test-classes
14[WARNING] ../jdk21/src/test/java/com/soebes/jdk21/TemplateTest.java:[12,23] string templates are a preview feature and may be removed in a future release.
15[WARNING] ../jdk21/src/test/java/com/soebes/jdk21/TemplateTest.java:[12,23] string templates are a preview feature and may be removed in a future release.
16[WARNING] using incubating module(s): jdk.incubator.vector
17[WARNING] ../jdk21/src/test/java/com/soebes/jdk21/TemplateTest.java:[5,24] java.lang.StringTemplate is a preview API and may be removed in a future release.
18[INFO] 
19[INFO] --- surefire:3.1.2:test (default-test) @ jdk21 ---
20[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider
21[INFO] 
22[INFO] -------------------------------------------------------
23[INFO]  T E S T S
24[INFO] -------------------------------------------------------
25WARNING: Using incubator modules: jdk.incubator.vector
26[INFO] Running com.soebes.jdk21.TemplateTest
27.. 

A small hint based on the usage of JDK21+. Starting with JDK21 the JEP-451 has been integrated into the JDK21 builds which means the usage of dynamic loaded agents for example the famous Mockito library results into WARNINGs as well which looks like this:

 1..
 2[INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.217 s -- in com.soebes.jdk21.SequencedCollectionTest
 3[INFO] Running com.soebes.jdk21.AFinalClassTest
 4OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended
 5WARNING: A Java agent has been loaded dynamically (/Users/khm/.m2/repository/net/bytebuddy/byte-buddy-agent/1.14.5/byte-buddy-agent-1.14.5.jar)
 6WARNING: If a serviceability tool is in use, please run with -XX:+EnableDynamicAgentLoading to hide this warning
 7WARNING: If a serviceability tool is not in use, please run with -Djdk.instrument.traceUsage for more information
 8WARNING: Dynamic loading of agents will be disallowed by default in a future release
 9[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.472 s -- in com.soebes.jdk21.AFinalClassTest
10[INFO] Running com.soebes.jdk21.incubator.VectorTest
11..

This makes it necessary to add the supplemental configuration -XX:+EnableDynamicAgentLoading to your maven-surefire-plugin configuration like this:

 1<plugin>
 2  <groupId>org.apache.maven.plugins</groupId>
 3  <artifactId>maven-surefire-plugin</artifactId>
 4  <configuration>
 5    <argLine>
 6      --enable-preview
 7      --add-modules jdk.incubator.vector
 8      -XX:+EnableDynamicAgentLoading
 9    </argLine>
10  </configuration>
11</plugin>

A full working example which obviously requires JDK21 most recent EA build can be found here:

https://github.com/khmarbaise/jdk21

Happy coding.