Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand All @@ -51,6 +53,11 @@ public void setClassPath(List<String> classPath) {
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();
Expand All @@ -59,6 +66,27 @@ private URL toUrl(String path) {
}
}

/**
* 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}
*/
Expand All @@ -76,10 +104,13 @@ public Object evaluateScript(String script, Map<String, ?> globalVariables, Prin
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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,18 @@ public void setClassPath(List<String> classPath) {
}
}

/**
* 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.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,24 @@ void evaluateScriptVars() throws Exception {
}
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"));
}
}