javafreemarkergraalvm-native-image

Unnecessary warnings for Freemarker classes on native image execution


I am developing a command line app with freemarker. I want to build the app as a graalvm native image using the native-maven-plugin. When I start the app on the command line (zsh on MacOS), I get the following warning:

Aug. 01, 2024 10:25:29 PM freemarker.log._JULLoggerFactory$JULLogger warn
WARNUNG: Seems that the Java 9 support class (freemarker.core._Java9Impl) wasn't included in the build

Aug. 01, 2024 10:25:29 PM freemarker.log._JULLoggerFactory$JULLogger warn
WARNUNG: Seems that the Java 16 support class (freemarker.core._Java16Impl) wasn't included in the build

I have already tried to include the two classes _Java9Impl and _Java16Impl in the image using the native image build option --initialise-at-build-time=org.freemarker._Java9Impl. Without success.

I have also tried to simply use the two classes in my application so that they are included in the native image. To do this, I added the following code to my app, which actually makes no sense:

_Java9 j9 = _Java9Impl.INSTANCE;
_Java16 j16 = _Java16Impl.INSTANCE;
if (LocalDate.now().isBefore(LocalDate.of(1970,1,1))) {
    System.out.println(j9.toString() + j16.toString());
}

Unfortunately without success, the two warnings are still displayed. What do I have to do to make the two warnings disappear?


Solution

  • It's not an "unnecessary warning", as it indicates that FreeMarker won't be able to use Java 9 and 16 features (such as module and record support).

    freemarker.jar is tricky, as all class-es in it are in Java 8 format, except the two classes you get the warning about, which are in Java 9 and 16 formats. FreeMarkerker detects the Java version on runtime, and loads those classes dynamically via Class.forName, if the runtime is high enough version. Apparently, when Class.forName("freemarker.core._Java9Impl") is called there, it throws ClassNotFoundException (and same with _Java16Impl). Maybe GraalVM Native doesn't support that?

    Anyway, in 2.3.34-SNAPSHOT I have switched to another technique now, "JEP 238: Multi-Release JAR Files". What that does is that there are two freemarker.core._Java9Imp classes in the jar. One is Java 8 and is at the usual place inside the jar, and the other is inside META-INF/versions/9, and is Java 9. Then I just link statically (normally) to _Java9Imp (and _Java16Imp), and the Java runtime will resolve it to the correct variant. So if that works for GraalVM Native, then _Java9.INSTANCE.isSupported() should return true (assuming Java 9+), and also _Java16.INSTANCE.isSupported() (assuming Java 16+). (The warning won't be logged anymore for sure, but it's a question if GraalVM Natiev will link to the proper variant of the ...Impl classes.)

    Can you try if this Multi-Release JAR approach works? (Code is pushed on Github, and also here's the snapshot repo: https://repository.apache.org/content/repositories/snapshots/org/freemarker/freemarker/2.3.34-SNAPSHOT/)