You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by sj...@apache.org on 2026/08/31 22:45:24 UTC

(maven-script-interpreter) branch master updated: Allow interpreters to target a specific bytecode version

This is an automated email from the ASF dual-hosted git repository.

slawekjaranowski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-script-interpreter.git


The following commit(s) were added to refs/heads/master by this push:
     new 15eabe2  Allow interpreters to target a specific bytecode version
15eabe2 is described below

commit 15eabe26b2dfc56009c016a3aa16b880d662cfbc
Author: adityaanikam <ad...@gmail.com>
AuthorDate: Wed Aug 5 23:44:12 2026 +0530

    Allow interpreters to target a specific bytecode version
    
    See apache/maven-invoker-plugin#742
    
    Signed-off-by: adityaanikam <ad...@gmail.com>
---
 .../scriptinterpreter/GroovyScriptInterpreter.java | 39 +++++++++++++++++++---
 .../scriptinterpreter/ScriptInterpreter.java       | 10 ++++++
 .../shared/scriptinterpreter/ScriptRunner.java     | 12 +++++++
 .../GroovyScriptInterpreterTest.java               | 20 +++++++++++
 4 files changed, 77 insertions(+), 4 deletions(-)

diff --git a/src/main/java/org/apache/maven/shared/scriptinterpreter/GroovyScriptInterpreter.java b/src/main/java/org/apache/maven/shared/scriptinterpreter/GroovyScriptInterpreter.java
index 3617572..abadea2 100644
--- a/src/main/java/org/apache/maven/shared/scriptinterpreter/GroovyScriptInterpreter.java
+++ b/src/main/java/org/apache/maven/shared/scriptinterpreter/GroovyScriptInterpreter.java
@@ -42,6 +42,8 @@ class GroovyScriptInterpreter implements ScriptInterpreter {
     private final RootLoader childFirstLoader =
             new RootLoader(new URL[] {}, Thread.currentThread().getContextClassLoader());
 
+    private String targetBytecode;
+
     @Override
     public void setClassPath(List<String> classPath) {
         if (classPath == null || classPath.isEmpty()) {
@@ -51,6 +53,11 @@ class GroovyScriptInterpreter implements ScriptInterpreter {
         classPath.stream().map(this::toUrl).forEach(childFirstLoader::addURL);
     }
 
+    @Override
+    public void setTargetBytecode(String version) {
+        this.targetBytecode = version;
+    }
+
     private URL toUrl(String path) {
         try {
             return new File(path).toURI().toURL();
@@ -59,6 +66,27 @@ class GroovyScriptInterpreter implements ScriptInterpreter {
         }
     }
 
+    /**
+     * Maps a Maven-style release value (for example <code>"8"</code>) to the version string Groovy's
+     * {@link CompilerConfiguration#setTargetBytecode(String)} expects (for example <code>"1.8"</code>). Groovy uses
+     * the <code>"1.x"</code> form for JDK 4 through 8, and bare version numbers from JDK 9 onward.
+     *
+     * @param version The Maven-style release value, must not be <code>null</code>.
+     * @return The Groovy-compatible bytecode version string.
+     */
+    static String normalizeTargetBytecode(String version) {
+        switch (version) {
+            case "4":
+            case "5":
+            case "6":
+            case "7":
+            case "8":
+                return "1." + version;
+            default:
+                return version;
+        }
+    }
+
     /**
      * {@inheritDoc}
      */
@@ -76,10 +104,13 @@ class GroovyScriptInterpreter implements ScriptInterpreter {
                 System.setOut(scriptOutput);
             }
 
-            GroovyShell interpreter = new GroovyShell(
-                    childFirstLoader,
-                    new Binding(globalVariables),
-                    new CompilerConfiguration(CompilerConfiguration.DEFAULT));
+            CompilerConfiguration compilerConfiguration = new CompilerConfiguration(CompilerConfiguration.DEFAULT);
+            if (targetBytecode != null) {
+                compilerConfiguration.setTargetBytecode(normalizeTargetBytecode(targetBytecode));
+            }
+
+            GroovyShell interpreter =
+                    new GroovyShell(childFirstLoader, new Binding(globalVariables), compilerConfiguration);
 
             Thread.currentThread().setContextClassLoader(childFirstLoader);
             return interpreter.evaluate(script);
diff --git a/src/main/java/org/apache/maven/shared/scriptinterpreter/ScriptInterpreter.java b/src/main/java/org/apache/maven/shared/scriptinterpreter/ScriptInterpreter.java
index 01cc14d..3ddcff8 100644
--- a/src/main/java/org/apache/maven/shared/scriptinterpreter/ScriptInterpreter.java
+++ b/src/main/java/org/apache/maven/shared/scriptinterpreter/ScriptInterpreter.java
@@ -41,6 +41,16 @@ public interface ScriptInterpreter extends Closeable {
      */
     void setClassPath(List<String> classPath);
 
+    /**
+     * Sets the target bytecode version for interpreters that support bytecode-level compilation. Interpreters
+     * that do not compile to a specific bytecode level (for example BeanShell) may ignore this.
+     *
+     * @param version The target bytecode version, may be <code>null</code> to use the interpreter's own default.
+     */
+    default void setTargetBytecode(String version) {
+        // no-op by default
+    }
+
     /**
      * Evaluates the specified script.
      *
diff --git a/src/main/java/org/apache/maven/shared/scriptinterpreter/ScriptRunner.java b/src/main/java/org/apache/maven/shared/scriptinterpreter/ScriptRunner.java
index a1ed3e8..2ef2f8e 100644
--- a/src/main/java/org/apache/maven/shared/scriptinterpreter/ScriptRunner.java
+++ b/src/main/java/org/apache/maven/shared/scriptinterpreter/ScriptRunner.java
@@ -104,6 +104,18 @@ public class ScriptRunner implements Closeable {
         }
     }
 
+    /**
+     * Sets the target bytecode version for the hook scripts, for interpreters that support bytecode-level
+     * compilation.
+     *
+     * @param version The target bytecode version, may be <code>null</code> to use each interpreter's own default.
+     */
+    public void setTargetBytecode(String version) {
+        if (version != null) {
+            scriptInterpreters.values().forEach(scriptInterpreter -> scriptInterpreter.setTargetBytecode(version));
+        }
+    }
+
     /**
      * Sets the file encoding of the hook scripts.
      *
diff --git a/src/test/java/org/apache/maven/shared/scriptinterpreter/GroovyScriptInterpreterTest.java b/src/test/java/org/apache/maven/shared/scriptinterpreter/GroovyScriptInterpreterTest.java
index 3bee0fa..fa78fdb 100644
--- a/src/test/java/org/apache/maven/shared/scriptinterpreter/GroovyScriptInterpreterTest.java
+++ b/src/test/java/org/apache/maven/shared/scriptinterpreter/GroovyScriptInterpreterTest.java
@@ -96,4 +96,24 @@ class GroovyScriptInterpreterTest {
         }
         assertEquals("data", out.toString());
     }
+
+    @Test
+    void evaluateScriptWithTargetBytecode() throws Exception {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        try (ScriptInterpreter interpreter = new GroovyScriptInterpreter()) {
+            interpreter.setTargetBytecode("8");
+            assertEquals(
+                    Boolean.TRUE,
+                    interpreter.evaluateScript("print \"Test\"\nreturn true", null, new PrintStream(out)));
+        }
+        assertEquals("Test", out.toString());
+    }
+
+    @Test
+    void normalizeTargetBytecodeMapsOldJdksToDotForm() {
+        assertEquals("1.4", GroovyScriptInterpreter.normalizeTargetBytecode("4"));
+        assertEquals("1.8", GroovyScriptInterpreter.normalizeTargetBytecode("8"));
+        assertEquals("9", GroovyScriptInterpreter.normalizeTargetBytecode("9"));
+        assertEquals("17", GroovyScriptInterpreter.normalizeTargetBytecode("17"));
+    }
 }