From 0ba9f25b0e5deb638f6e7472141f4edc4450c99b Mon Sep 17 00:00:00 2001 From: Alexander Kriegisch Date: Fri, 15 Dec 2023 14:56:50 +0700 Subject: [PATCH] Add minimal JRE version check to Main.runMain Use new constant Main.MINIMAL_JRE_VERSION (currently = 17) and SourceVersion.latest().ordinal() to check, if the minimal JRE version requirement for AJC is met. If not, then exit with code -1 and error message "The AspectJ compiler needs at least Java runtime 17". Relates to #269. Signed-off-by: Alexander Kriegisch --- .../main/java/org/aspectj/tools/ajc/Main.java | 56 ++++++++++++------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/org.aspectj.ajdt.core/src/main/java/org/aspectj/tools/ajc/Main.java b/org.aspectj.ajdt.core/src/main/java/org/aspectj/tools/ajc/Main.java index de69b6d37..29ecacc89 100644 --- a/org.aspectj.ajdt.core/src/main/java/org/aspectj/tools/ajc/Main.java +++ b/org.aspectj.ajdt.core/src/main/java/org/aspectj/tools/ajc/Main.java @@ -38,6 +38,8 @@ import org.aspectj.util.FileUtil; import org.aspectj.util.LangUtil; import org.aspectj.weaver.Dump; +import javax.lang.model.SourceVersion; + /** * Programmatic and command-line interface to AspectJ compiler. The compiler is an ICommand obtained by reflection. Not thread-safe. * By default, messages are printed as they are emitted; info messages go to the output stream, and warnings and errors go to the @@ -79,6 +81,12 @@ public class Main { private static final String MESSAGE_HOLDER_OPTION = "-messageHolder"; + // Minimal Java runtime version necessary to run AJC + // TODO: Update value, if Eclipse JDT Core raises compilation target level. + private static final int MINIMAL_JRE_VERSION = 17; + private static final String MINIMAL_JRE_VERSION_ERROR = + "The AspectJ compiler needs at least Java runtime " + MINIMAL_JRE_VERSION; + /** @param args the String[] of command-line arguments */ public static void main(String[] args) throws IOException { new Main().runMain(args, true); @@ -218,14 +226,31 @@ public class Main { } /** - * Run without throwing exceptions but optionally using System.exit(..). This sets up a message handler which emits messages - * immediately, so report(boolean, IMessageHandler) only reports total number of errors or warnings. + * Run without throwing exceptions, but optionally using {@link System#exit(int)}. This sets up a message handler + * which emits messages immediately, so {@link #report(boolean, IMessageHolder)} only reports the total number of + * errors or warnings. * - * @param args the String[] command line for the compiler - * @param useSystemExit if true, use System.exit(int) to complete unless one of the args is -noExit. and signal result (0 no - * exceptions/error, <0 exceptions, >0 compiler errors). + * @param args the compiler command line + * @param useSystemExit if true, use {@link System#exit(int)} to complete unless one of the args is {@code -noExit}, + * and signal result (0 = no exceptions/error, <0 = exceptions, >0 = compiler errors). + * Note: While some shells like Windows cmd.exe can correctly print negative exit codes + * via {@code echo %errorlevel%"}, UNIX shells like Bash interpret them as positive byte values + * modulo 256. E.g., exit code -1 will be printed as 127 using {@code echo $?}. */ public void runMain(String[] args, boolean useSystemExit) { + final boolean doExit = useSystemExit && !flagInArgs("-noExit", args); + + // This needs to be checked, before any classes using JDT Core classes are used for the first time. Otherwise, users + // will see ugly UnsupportedClassVersionError stack traces, which they might or might not interpret correctly. + // Therefore, interrupt AJC usage right here, even if it means that not even a usage page can be printed. It is + // better to save users from subsequent problems later. + if (SourceVersion.latest().ordinal() < MINIMAL_JRE_VERSION) { + System.err.println(MINIMAL_JRE_VERSION_ERROR); + if (doExit) + System.exit(-1); + return; + } + // Urk - default no check for AJDT, enabled here for Ant, command-line AjBuildManager.enableRuntimeVersionCheck(this); final boolean verbose = flagInArgs("-verbose", args); @@ -267,18 +292,8 @@ public class Main { Dump.reset(); } - boolean skipExit = false; - if (useSystemExit && !LangUtil.isEmpty(args)) { // sigh - pluck -noExit - for (String arg : args) { - if ("-noExit".equals(arg)) { - skipExit = true; - break; - } - } - } - if (useSystemExit && !skipExit) { - systemExit(holder); - } + if (doExit) + systemExit(); } // put calls around run() call above to allowing connecting jconsole @@ -453,14 +468,13 @@ public class Main { /** * Call System.exit(int) with values derived from the number of failures/aborts or errors in messages. * - * @param messages the IMessageHolder to interrogate. */ - protected void systemExit(IMessageHolder messages) { - int num = lastFails; // messages.numMessages(IMessage.FAIL, true); + protected void systemExit() { + int num = lastFails; if (0 < num) { System.exit(-num); } - num = lastErrors; // messages.numMessages(IMessage.ERROR, false); + num = lastErrors; if (0 < num) { System.exit(num); } -- 2.39.5