Frgaal

From APIDesign

(Difference between revisions)
Jump to: navigation, search
(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.io.InputStream;
 
-
import java.io.OutputStream;
 
-
import java.io.Reader;
 
-
import java.io.Writer;
 
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.lang.model.element.Modifier;
 
-
import javax.lang.model.element.NestingKind;
 
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 implements JavaFileObject {
+
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
+
-
public Kind getKind() {
+
-
return Kind.SOURCE;
+
-
}
+
-
 
+
-
@Override
+
-
public boolean isNameCompatible(String string, Kind kind) {
+
-
return false;
+
-
}
+
-
 
+
-
@Override
+
-
public NestingKind getNestingKind() {
+
-
return NestingKind.TOP_LEVEL;
+
-
}
+
-
 
+
-
@Override
+
-
public Modifier getAccessLevel() {
+
-
return Modifier.PUBLIC;
+
-
}
+
-
 
+
-
@Override
+
-
public URI toUri() {
+
-
try {
+
-
return new URI("memory://Code.java");
+
-
} catch (URISyntaxException ex) {
+
-
throw new IllegalStateException(ex);
+
-
}
+
-
}
+
-
 
+
@Override
@Override
public String getName() {
public String getName() {
return "Code.java";
return "Code.java";
}
}
-
 
+
-
@Override
+
-
public InputStream openInputStream() throws IOException {
+
-
throw new UnsupportedOperationException();
+
-
}
+
-
 
+
-
@Override
+
-
public OutputStream openOutputStream() throws IOException {
+
-
throw new UnsupportedOperationException();
+
-
}
+
-
 
+
-
@Override
+
-
public Reader openReader(boolean bln) throws IOException {
+
-
throw new UnsupportedOperationException();
+
-
}
+
-
 
+
@Override
@Override
public CharSequence getCharContent(boolean bln) throws IOException {
public CharSequence getCharContent(boolean bln) throws IOException {
return code;
return code;
}
}
-
 
-
@Override
 
-
public Writer openWriter() throws IOException {
 
-
throw new UnsupportedOperationException();
 
-
}
 
-
 
-
@Override
 
-
public long getLastModified() {
 
-
throw new UnsupportedOperationException();
 
-
}
 
-
 
-
@Override
 
-
public boolean delete() {
 
-
throw new UnsupportedOperationException();
 
-
}
 
-
 
}
}
}
}

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!

Personal tools
buy