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?
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/)