Frgaal
From APIDesign
(→Can I use Frgaal via {{JDK|javax/tools|ToolProvider}} API?) |
|||
Line 7: | Line 7: | ||
<source lang="java"> | <source lang="java"> | ||
- | |||
import java.io.IOException; | import java.io.IOException; | ||
- | |||
- | |||
- | |||
- | |||
import java.net.URI; | import java.net.URI; | ||
import java.net.URISyntaxException; | import java.net.URISyntaxException; | ||
Line 18: | Line 13: | ||
import java.util.Collections; | import java.util.Collections; | ||
import java.util.List; | import java.util.List; | ||
- | |||
- | |||
import javax.tools.JavaCompiler; | import javax.tools.JavaCompiler; | ||
import javax.tools.JavaFileObject; | import javax.tools.JavaFileObject; | ||
- | + | import javax.tools.SimpleJavaFileObject; | |
+ | |||
class ModernJavaCompiler { | class ModernJavaCompiler { | ||
private static final String CODE = "record R (String name) {}"; | private static final String CODE = "record R (String name) {}"; | ||
- | + | ||
- | public static void main(String... args) { | + | public static void main(String... args) throws Exception { |
JavaCompiler compiler = javax.tools.ToolProvider.getSystemJavaCompiler(); | JavaCompiler compiler = javax.tools.ToolProvider.getSystemJavaCompiler(); | ||
List<String> itrbl = Arrays.asList("-source", "17", "-target", "8"); | List<String> itrbl = Arrays.asList("-source", "17", "-target", "8"); | ||
Line 39: | Line 33: | ||
} | } | ||
} | } | ||
- | + | ||
- | static class Src | + | static class Src extends SimpleJavaFileObject { |
private final String code; | private final String code; | ||
- | + | ||
- | public Src(String code) { | + | public Src(String code) throws URISyntaxException { |
+ | super(new URI("memory://Code.java"), Kind.SOURCE); | ||
this.code = code; | this.code = code; | ||
} | } | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
@Override | @Override | ||
public String getName() { | public String getName() { | ||
return "Code.java"; | return "Code.java"; | ||
} | } | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
@Override | @Override | ||
public CharSequence getCharContent(boolean bln) throws IOException { | public CharSequence getCharContent(boolean bln) throws IOException { | ||
return code; | return code; | ||
} | } | ||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
} | } | ||
} | } |
Revision as of 12:57, 22 April 2022
I love Frgaal and you'll love it too: Wouldn't it be great to have the latest Java language features available on your old JDK? As old as JDK8? Frgaal allows you to do it. There is a Maven plugin, integration with Gradle, a way to use it from command line... read more at http://frgaal.org
Can I use Frgaal via ToolProvider API?
Given following code (that invokes the JavaCompiler via ToolProvider for a custom CODE snippet that uses JDK17 Record:
import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.Arrays; import java.util.Collections; import java.util.List; import javax.tools.JavaCompiler; import javax.tools.JavaFileObject; import javax.tools.SimpleJavaFileObject; class ModernJavaCompiler { private static final String CODE = "record R (String name) {}"; public static void main(String... args) throws Exception { JavaCompiler compiler = javax.tools.ToolProvider.getSystemJavaCompiler(); List<String> itrbl = Arrays.asList("-source", "17", "-target", "8"); List<String> itrbl1 = null; List<JavaFileObject> itrbl2 = Collections.singletonList(new Src(CODE)); JavaCompiler.CompilationTask task = compiler.getTask(null, null, null, itrbl, itrbl1, itrbl2); Boolean res = task.call(); if (!Boolean.TRUE.equals(res)) { throw new IllegalStateException("Compilation failed: " + res); } else { System.out.println("Compiled OK"); } } static class Src extends SimpleJavaFileObject { private final String code; public Src(String code) throws URISyntaxException { super(new URI("memory://Code.java"), Kind.SOURCE); this.code = code; } @Override public String getName() { return "Code.java"; } @Override public CharSequence getCharContent(boolean bln) throws IOException { return code; } } }
This is a Java class that can be compiled using
javac -source 8 -target 8 ModernJavaCompiler.java
Then it can be executed on JDK-17 as
$ /jdk-17/bin/java ModernJavaCompiler Compiled OK
However executing the same code on JDK-11 is going to fail (as the Javac from JDK-11 doesn't support -source 17):
$ /jdk11/bin/java ModernJavaCompiler Exception in thread "main" java.lang.IllegalArgumentException: error: invalid source release: 17 at jdk.compiler/com.sun.tools.javac.main.Arguments.error(Arguments.java:907) at jdk.compiler/com.sun.tools.javac.main.Arguments.doProcessArgs(Arguments.java:383) at jdk.compiler/com.sun.tools.javac.main.Arguments.processArgs(Arguments.java:347) at jdk.compiler/com.sun.tools.javac.main.Arguments.init(Arguments.java:246) at jdk.compiler/com.sun.tools.javac.api.JavacTool.getTask(JavacTool.java:185) at jdk.compiler/com.sun.tools.javac.api.JavacTool.getTask(JavacTool.java:119) at jdk.compiler/com.sun.tools.javac.api.JavacTool.getTask(JavacTool.java:68) at ModernJavaCompiler.main(ModernJavaCompiler.java:23)
The idea would be to replace the standard "compiler tool" with one coming from the frgaal. Let's try to disable the regular compiler first. There is an option --limit-modules in JDK-11+ and the idea is to use it to use it to disable standard JavaC:
$ /jdk11/bin/java --limit-modules java.base ModernJavaCompiler Exception in thread "main" java.lang.NoClassDefFoundError: javax/tools/ToolProvider
Great! The disabling works. The "compiler tool" is completely missing. Now there is a time to inject Frgaal instead. Following script shows how to get it all working:
$ mkdir -p META-INF/services $ echo com.sun.tools.javac.api.JavacTool > META-INF/services/javax.tools.JavaCompiler $ curl -o compiler.jar https://repo1.maven.org/maven2/org/frgaal/compiler/18.0.0/compiler-18.0.0.jar $ /jdk-11/bin/java --limit-modules java.base,jdk.zipfs -cp compiler.jar:. ModernJavaCompiler warning: [options] system modules path not set in conjunction with -source 17 warning: No output directory specified, cannot perform multi-release compilation 2 warnings Compiled OK
E.g. it is necessary to provide extra ServiceLoader registration in META-INF/services path on the class path, but then it seems to run. Embed Frgaal into your own programs and use the latest Java features on any JDK!