or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/maven-org-apache-groovy--groovy-jsr223

JSR-223 (Scripting for the Java Platform) implementation for Apache Groovy

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
mavenpkg:maven/org.apache.groovy/groovy-jsr223@5.0.x

To install, run

npx @tessl/cli install tessl/maven-org-apache-groovy--groovy-jsr223@5.0.0

index.mddocs/

Groovy JSR-223 Script Engine

A JSR-223 (Java Specification Request 223 - Scripting for the Java Platform) compliant script engine implementation for Apache Groovy. This package enables Java applications to execute Groovy scripts through the standard javax.script API, providing seamless integration between Java and Groovy code.

Package Information

  • Package Name: org.apache.groovy:groovy-jsr223
  • Package Type: Maven
  • Language: Java
  • Installation:
    • Maven:
      <dependency>
        <groupId>org.apache.groovy</groupId>
        <artifactId>groovy-jsr223</artifactId>
        <version>5.0.0</version>
      </dependency>
    • Gradle:
      implementation 'org.apache.groovy:groovy-jsr223:5.0.0'

Core Imports

import javax.script.ScriptEngineManager;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.Invocable;
import org.codehaus.groovy.jsr223.GroovyScriptEngineFactory;
import org.codehaus.groovy.jsr223.GroovyScriptEngineImpl;
import org.codehaus.groovy.control.CompilationFailedException;

For extension methods:

import org.codehaus.groovy.jsr223.ScriptExtensions;
import org.codehaus.groovy.jsr223.ScriptStaticExtensions;
import groovy.lang.Binding;

Basic Usage

import javax.script.*;

// Get Groovy script engine through ScriptEngineManager
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("groovy");

// Execute simple script
Object result = engine.eval("2 + 3");
System.out.println(result); // Outputs: 5

// Execute script with variables
engine.put("x", 10);
engine.put("y", 20);
Object sum = engine.eval("x + y");
System.out.println(sum); // Outputs: 30

// Execute script with more complex logic
String script = """
    def greet(name) {
        return "Hello, ${name}!"
    }
    greet('World')
""";
Object greeting = engine.eval(script);
System.out.println(greeting); // Outputs: Hello, World!

// Compile and reuse scripts
Compilable compilable = (Compilable) engine;
CompiledScript compiled = compilable.compile("Math.sqrt(x)");

engine.put("x", 16);
Object result1 = compiled.eval(); // 4.0

engine.put("x", 25);
Object result2 = compiled.eval(); // 5.0

Architecture

The Groovy JSR-223 implementation consists of several key components:

  • GroovyScriptEngineFactory: JSR-223 factory class that creates script engine instances and provides metadata about the Groovy scripting engine
  • GroovyScriptEngineImpl: Main script engine implementation providing script evaluation, compilation, and invocation capabilities
  • GroovyCompiledScript: Represents pre-compiled Groovy scripts for efficient repeated execution
  • Extension Classes: Provide enhanced integration between Groovy Binding objects and JSR-223 script contexts
  • Service Registration: Automatic discovery through META-INF/services mechanism

This design provides full JSR-223 compliance while leveraging Groovy's dynamic capabilities and maintaining compatibility with existing Java scripting infrastructure.

Capabilities

Script Engine Factory

Factory class for creating Groovy script engines and providing engine metadata.

public class GroovyScriptEngineFactory implements ScriptEngineFactory {
    public String getEngineName();
    public String getEngineVersion();
    public String getLanguageName();
    public String getLanguageVersion();
    public List<String> getExtensions();
    public List<String> getMimeTypes();
    public List<String> getNames();
    public Object getParameter(String key);
    public ScriptEngine getScriptEngine();
    public String getMethodCallSyntax(String obj, String method, String... args);
    public String getOutputStatement(String toDisplay);
    public String getProgram(String... statements);
}

Usage Example:

GroovyScriptEngineFactory factory = new GroovyScriptEngineFactory();

// Get engine metadata
System.out.println(factory.getEngineName()); // "Groovy Scripting Engine"
System.out.println(factory.getLanguageName()); // "Groovy"
System.out.println(factory.getExtensions()); // ["groovy"]
System.out.println(factory.getMimeTypes()); // ["application/x-groovy"]

// Generate syntax examples
String methodCall = factory.getMethodCallSyntax("obj", "doSomething", "arg1", "arg2");
System.out.println(methodCall); // "obj.doSomething(arg1,arg2)"

String output = factory.getOutputStatement("Hello World");
System.out.println(output); // "println(\"Hello World\")"

// Create script engine
ScriptEngine engine = factory.getScriptEngine();

Script Engine Implementation

Main JSR-223 script engine providing evaluation, compilation, and invocation capabilities.

public class GroovyScriptEngineImpl extends AbstractScriptEngine 
    implements Compilable, Invocable {
    
    // Constructors
    public GroovyScriptEngineImpl();
    public GroovyScriptEngineImpl(GroovyClassLoader classLoader);
    
    // ScriptEngine methods
    public Object eval(Reader reader, ScriptContext ctx) throws ScriptException;
    public Object eval(String script, ScriptContext ctx) throws ScriptException;
    public Bindings createBindings();
    public ScriptEngineFactory getFactory();
    
    // Compilable methods
    public CompiledScript compile(String scriptSource) throws ScriptException;
    public CompiledScript compile(Reader reader) throws ScriptException;
    
    // Invocable methods
    public Object invokeFunction(String name, Object... args) 
        throws ScriptException, NoSuchMethodException;
    public Object invokeMethod(Object thiz, String name, Object... args) 
        throws ScriptException, NoSuchMethodException;
    public <T> T getInterface(Class<T> clazz);
    public <T> T getInterface(Object thiz, Class<T> clazz);
    
    // Script class management methods
    public Class<?> getScriptClass(String script) throws CompilationFailedException;
    public Class<?> getScriptClass(String script, ScriptContext context) 
        throws CompilationFailedException;
    
    // Utility methods
    public void setClassLoader(GroovyClassLoader classLoader);
    public GroovyClassLoader getClassLoader();
}

Usage Example:

// Direct instantiation
GroovyScriptEngineImpl engine = new GroovyScriptEngineImpl();

// Function invocation
engine.eval("def multiply(a, b) { return a * b }");
Invocable invocable = (Invocable) engine;
Object result = invocable.invokeFunction("multiply", 5, 3); // 15

// Method invocation on objects
engine.eval("""
    class Calculator {
        def add(a, b) { return a + b }
        def subtract(a, b) { return a - b }
    }
    calc = new Calculator()
""");
Object calculator = engine.get("calc");
Object sum = invocable.invokeMethod(calculator, "add", 10, 5); // 15

// Interface proxy
engine.eval("""
    def hello(name) { return "Hello, ${name}!" }
    def goodbye(name) { return "Goodbye, ${name}!" }
""");

interface Greeter {
    String hello(String name);
    String goodbye(String name);
}

Greeter greeter = invocable.getInterface(Greeter.class);
System.out.println(greeter.hello("Alice")); // "Hello, Alice!"

// Access to script class compilation
GroovyScriptEngineImpl groovyEngine = (GroovyScriptEngineImpl) engine;
Class<?> scriptClass = groovyEngine.getScriptClass("def hello() { 'Hello World' }");
System.out.println(scriptClass.getName()); // Generated class name

// Script class compilation with context
ScriptContext context = engine.getContext();
context.setAttribute(ScriptEngine.FILENAME, "MyScript.groovy", ScriptContext.ENGINE_SCOPE);
Class<?> namedClass = groovyEngine.getScriptClass("def greet() { 'Greetings!' }", context);

Compiled Scripts

Pre-compiled Groovy scripts for efficient repeated execution.

public class GroovyCompiledScript extends CompiledScript {
    public GroovyCompiledScript(GroovyScriptEngineImpl engine, Class<?> clazz);
    public Object eval(ScriptContext context) throws ScriptException;
    public ScriptEngine getEngine();
}

Usage Example:

ScriptEngine engine = new ScriptEngineManager().getEngineByName("groovy");
Compilable compilable = (Compilable) engine;

// Compile script once
CompiledScript compiled = compilable.compile("""
    def processData(data) {
        return data.collect { it * 2 }.findAll { it > 10 }
    }
    processData(input)
""");

// Execute multiple times with different inputs
engine.put("input", Arrays.asList(1, 2, 5, 8, 10));
Object result1 = compiled.eval(); // [16, 20]

engine.put("input", Arrays.asList(3, 6, 9, 12));
Object result2 = compiled.eval(); // [12, 18, 24]

Script Extensions

Extension methods providing enhanced integration between ScriptEngine and Groovy Binding.

public class ScriptExtensions {
    public static Object eval(ScriptEngine self, String script, Binding binding) 
        throws ScriptException;
    public static Object eval(ScriptEngine self, Reader reader, Binding binding) 
        throws ScriptException;
}

Usage Example:

import static org.codehaus.groovy.jsr223.ScriptExtensions.eval;

ScriptEngine engine = new ScriptEngineManager().getEngineByName("groovy");
Binding binding = new Binding();

// Set variables in Groovy binding
binding.setVariable("name", "Alice");
binding.setVariable("age", 25);

// Execute script with binding integration
Object result = eval(engine, "\"${name} is ${age} years old\"", binding);
System.out.println(result); // "Alice is 25 years old"

// Variables modified in script are reflected back in binding
eval(engine, "name = name.toUpperCase(); newVar = 'created'", binding);
System.out.println(binding.getVariable("name")); // "ALICE"
System.out.println(binding.getVariable("newVar")); // "created"

Static Extensions

Static extension methods for ScriptEngineManager providing dynamic engine access.

public class ScriptStaticExtensions {
    public static ScriptEngine $static_propertyMissing(
        ScriptEngineManager self, String languageShortName);
}

Usage Example:

// This enables dynamic property access syntax in Groovy code:
// manager.groovy instead of manager.getEngineByName("groovy")

// Standard JSR-223 approach
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine groovyEngine = manager.getEngineByName("groovy");
ScriptEngine jsEngine = manager.getEngineByName("javascript");

// With static extensions (in Groovy code):
// ScriptEngine groovyEngine = manager.groovy
// ScriptEngine jsEngine = manager.javascript

Error Handling

The implementation provides comprehensive error handling for various scenarios:

ScriptEngine engine = new ScriptEngineManager().getEngineByName("groovy");

try {
    // Script compilation errors
    engine.eval("def invalid syntax here");
} catch (ScriptException e) {
    System.err.println("Script compilation failed: " + e.getMessage());
}

try {
    // Function invocation errors
    Invocable invocable = (Invocable) engine;
    invocable.invokeFunction("nonExistentFunction");
} catch (NoSuchMethodException e) {
    System.err.println("Function not found: " + e.getMessage());
} catch (ScriptException e) {
    System.err.println("Script execution failed: " + e.getMessage());
}

try {
    // Invalid parameters
    GroovyScriptEngineFactory factory = new GroovyScriptEngineFactory();
    factory.getParameter("INVALID_KEY");
} catch (IllegalArgumentException e) {
    System.err.println("Invalid parameter key: " + e.getMessage());
}

Common Exceptions:

  • ScriptException: Script compilation or execution errors
  • NoSuchMethodException: Missing function/method invocations
  • IllegalArgumentException: Invalid parameters or arguments
  • NullPointerException: Null method names in invocations

Configuration Options

Reference Management

Control memory management for global closures:

ScriptEngine engine = new ScriptEngineManager().getEngineByName("groovy");

// Configure closure reference strength
engine.getContext().setAttribute(
    "#jsr223.groovy.engine.keep.globals", 
    "weak", // Options: "hard", "soft", "weak", "phantom"
    ScriptContext.ENGINE_SCOPE
);

Custom ClassLoader

Use custom ClassLoader for script compilation:

GroovyClassLoader customLoader = new GroovyClassLoader();
GroovyScriptEngineImpl engine = new GroovyScriptEngineImpl(customLoader);

// Or modify existing engine
engine.setClassLoader(customLoader);

Thread Safety

The Groovy JSR-223 implementation provides:

  • MULTITHREADED support as indicated by the THREADING parameter
  • Thread-safe script class caching using concurrent maps
  • Safe concurrent execution of compiled scripts
  • Proper synchronization of ScriptContext access
// Multiple threads can safely share a compiled script
CompiledScript compiled = ((Compilable) engine).compile("Math.random()");

// Each thread should use its own ScriptContext for variable isolation
ExecutorService executor = Executors.newFixedThreadPool(10);
for (int i = 0; i < 100; i++) {
    executor.submit(() -> {
        try {
            ScriptContext context = new SimpleScriptContext();
            Object result = compiled.eval(context);
            System.out.println("Random: " + result);
        } catch (ScriptException e) {
            e.printStackTrace();
        }
    });
}

Types

// Core JSR-223 interfaces implemented
interface ScriptEngineFactory {
    String getEngineName();
    String getEngineVersion();
    String getLanguageName();
    String getLanguageVersion();
    List<String> getExtensions();
    List<String> getMimeTypes();
    List<String> getNames();
    Object getParameter(String key);
    ScriptEngine getScriptEngine();
    String getMethodCallSyntax(String obj, String method, String... args);
    String getOutputStatement(String toDisplay);
    String getProgram(String... statements);
}

interface ScriptEngine {
    Object eval(String script) throws ScriptException;
    Object eval(Reader reader) throws ScriptException;
    Object eval(String script, ScriptContext context) throws ScriptException;
    Object eval(Reader reader, ScriptContext context) throws ScriptException;
    void put(String key, Object value);
    Object get(String key);
    Bindings getBindings(int scope);
    void setBindings(Bindings bindings, int scope);
    Bindings createBindings();
    ScriptContext getContext();
    void setContext(ScriptContext context);
    ScriptEngineFactory getFactory();
}

interface Compilable {
    CompiledScript compile(String script) throws ScriptException;
    CompiledScript compile(Reader script) throws ScriptException;
}

interface Invocable {
    Object invokeMethod(Object thiz, String name, Object... args) 
        throws ScriptException, NoSuchMethodException;
    Object invokeFunction(String name, Object... args) 
        throws ScriptException, NoSuchMethodException;
    <T> T getInterface(Class<T> clazz);
    <T> T getInterface(Object thiz, Class<T> clazz);
}

abstract class CompiledScript {
    public abstract Object eval(ScriptContext context) throws ScriptException;
    public Object eval() throws ScriptException;
    public abstract ScriptEngine getEngine();
}

// Groovy-specific types
class Binding {
    public Binding();
    public Binding(Map variables);
    public Object getVariable(String name);
    public void setVariable(String name, Object value);
    public Map getVariables();
}

class GroovyClassLoader extends ClassLoader {
    public GroovyClassLoader();
    public GroovyClassLoader(ClassLoader parent);
    public Class<?> parseClass(String text, String fileName);
}

// Exception types
class CompilationFailedException extends RuntimeException {
    public CompilationFailedException(String message);
    public CompilationFailedException(String message, Throwable cause);
}