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!