Jython is an implementation of Python 2.7 written in 100% Pure Java, providing seamless integration with the Java platform and ecosystem.
—
Jython provides full support for the Java Scripting API (JSR-223), allowing seamless integration with existing Java applications that use the standard scripting framework.
The factory class for creating Jython script engines.
public class PyScriptEngineFactory implements ScriptEngineFactory {
// Engine metadata
public String getEngineName(); // Returns "jython"
public String getEngineVersion(); // Returns Jython version
public String getLanguageName(); // Returns "python"
public String getLanguageVersion(); // Returns Python version "2.7"
public List<String> getExtensions(); // Returns ["py"]
public List<String> getMimeTypes(); // Returns Python MIME types
public List<String> getNames(); // Returns ["python", "jython"]
// Script engine creation
public ScriptEngine getScriptEngine();
// Utility methods
public String getMethodCallSyntax(String obj, String m, String... args);
public String getOutputStatement(String toDisplay);
public String getProgram(String... statements);
public Object getParameter(String key);
}The main JSR-223 script engine implementation for Jython.
public class PyScriptEngine extends AbstractScriptEngine
implements Compilable, Invocable, AutoCloseable {
// Script execution
public Object eval(String script) throws ScriptException;
public Object eval(String script, ScriptContext context) throws ScriptException;
public Object eval(Reader reader) throws ScriptException;
public Object eval(Reader reader, ScriptContext context) throws ScriptException;
// Compilation support (Compilable interface)
public CompiledScript compile(String script) throws ScriptException;
public CompiledScript compile(Reader reader) throws ScriptException;
// Function invocation (Invocable interface)
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> clasz);
public <T> T getInterface(Object thiz, Class<T> clasz);
// Engine management
public Bindings createBindings();
public ScriptEngineFactory getFactory();
public void close();
}Provides variable scoping and bindings for the JSR-223 engine.
public final class PyScriptEngineScope extends PyObject implements Bindings {
// Bindings interface implementation
public Object put(String key, Object value);
public Object get(Object key);
public Object remove(Object key);
public boolean containsKey(Object key);
public boolean containsValue(Object value);
public Set<String> keySet();
public Collection<Object> values();
public Set<Entry<String, Object>> entrySet();
public int size();
public boolean isEmpty();
public void clear();
public void putAll(Map<? extends String, ? extends Object> toMerge);
}import javax.script.*;
public class JSR223Example {
public static void main(String[] args) throws ScriptException {
// Get script engine manager
ScriptEngineManager manager = new ScriptEngineManager();
// Get Jython engine by name
ScriptEngine engine = manager.getEngineByName("python");
// Execute simple script
engine.eval("print('Hello from Jython!')");
// Set variables
engine.put("name", "World");
engine.put("number", 42);
// Use variables in script
Object result = engine.eval("greeting = f'Hello, {name}! The answer is {number}'");
Object greeting = engine.get("greeting");
System.out.println("Result: " + greeting);
}
}ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("python");
// Create custom context
ScriptContext context = new SimpleScriptContext();
Bindings bindings = engine.createBindings();
bindings.put("x", 10);
bindings.put("y", 20);
context.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
// Execute with custom context
Object result = engine.eval("result = x + y", context);
Object sum = context.getAttribute("result");
System.out.println("Sum: " + sum); // Sum: 30Pre-compile scripts for better performance when executing multiple times.
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("python");
// Check if engine supports compilation
if (engine instanceof Compilable) {
Compilable compilable = (Compilable) engine;
// Compile script
CompiledScript compiled = compilable.compile("""
def calculate(x, y):
return x * y + (x - y)
result = calculate(a, b)
""");
// Execute compiled script multiple times
engine.put("a", 5);
engine.put("b", 3);
compiled.eval();
System.out.println("Result 1: " + engine.get("result")); // 17
engine.put("a", 10);
engine.put("b", 4);
compiled.eval();
System.out.println("Result 2: " + engine.get("result")); // 46
}CompiledScript compiled = compilable.compile("x ** 2 + y ** 2");
// Execute with different contexts
ScriptContext ctx1 = new SimpleScriptContext();
ctx1.setAttribute("x", 3, ScriptContext.ENGINE_SCOPE);
ctx1.setAttribute("y", 4, ScriptContext.ENGINE_SCOPE);
Object result1 = compiled.eval(ctx1);
System.out.println("3² + 4² = " + result1); // 25
ScriptContext ctx2 = new SimpleScriptContext();
ctx2.setAttribute("x", 5, ScriptContext.ENGINE_SCOPE);
ctx2.setAttribute("y", 12, ScriptContext.ENGINE_SCOPE);
Object result2 = compiled.eval(ctx2);
System.out.println("5² + 12² = " + result2); // 169Call Python functions directly from Java using the Invocable interface.
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("python");
// Define Python functions
engine.eval("""
def add(x, y):
return x + y
def greet(name, title=""):
if title:
return f"Hello, {title} {name}!"
else:
return f"Hello, {name}!"
class Calculator:
def __init__(self, factor=1):
self.factor = factor
def multiply(self, x):
return x * self.factor
calc = Calculator(10)
""");
// Invoke functions
if (engine instanceof Invocable) {
Invocable invocable = (Invocable) engine;
// Call simple function
Object sum = invocable.invokeFunction("add", 5, 3);
System.out.println("Sum: " + sum); // 8
// Call function with keyword-like behavior (positional only in JSR-223)
Object greeting1 = invocable.invokeFunction("greet", "Alice");
Object greeting2 = invocable.invokeFunction("greet", "Bob", "Dr.");
System.out.println(greeting1); // Hello, Alice!
System.out.println(greeting2); // Hello, Dr. Bob!
// Call method on object
Object calcInstance = engine.get("calc");
Object product = invocable.invokeMethod(calcInstance, "multiply", 7);
System.out.println("Product: " + product); // 70
}Create Java interfaces implemented by Python objects.
// Define Java interface
interface MathOperations {
double calculate(double x, double y);
String getOperationName();
}
// Define Python implementation
engine.eval("""
class Adder:
def calculate(self, x, y):
return x + y
def getOperationName(self):
return "Addition"
adder = Adder()
""");
// Get interface implementation
MathOperations mathOps = invocable.getInterface(
engine.get("adder"),
MathOperations.class
);
// Use as Java interface
double result = mathOps.calculate(10.5, 5.3);
String opName = mathOps.getOperationName();
System.out.println(opName + ": " + result); // Addition: 15.8ScriptEngine engine = manager.getEngineByName("python");
// Create custom bindings with initial values
Bindings customBindings = new SimpleBindings();
customBindings.put("PI", Math.PI);
customBindings.put("E", Math.E);
customBindings.put("logger", LoggerFactory.getLogger("jython"));
// Set as engine scope
engine.setBindings(customBindings, ScriptContext.ENGINE_SCOPE);
engine.eval("""
import math
# Use Java objects in Python
logger.info("Calculating circle area")
radius = 5
area = PI * radius * radius
logger.info(f"Area of circle with radius {radius} is {area}")
""");ScriptEngineManager manager = new ScriptEngineManager();
// Create multiple engines
ScriptEngine engine1 = manager.getEngineByName("python");
ScriptEngine engine2 = manager.getEngineByName("python");
// Shared data object
Map<String, Object> sharedData = new ConcurrentHashMap<>();
// Setup engines with shared data
engine1.put("shared", sharedData);
engine2.put("shared", sharedData);
// Engine 1 sets data
engine1.eval("shared['message'] = 'Hello from Engine 1'");
// Engine 2 reads data
engine2.eval("print('Engine 2 received:', shared.get('message'))");ScriptEngine engine = manager.getEngineByName("python");
try {
engine.eval("undefined_variable + 1");
} catch (ScriptException e) {
System.out.println("Script error: " + e.getMessage());
System.out.println("Line number: " + e.getLineNumber());
System.out.println("Column number: " + e.getColumnNumber());
System.out.println("File name: " + e.getFileName());
// Get the underlying Python exception
Throwable cause = e.getCause();
if (cause instanceof PyException) {
PyException pyEx = (PyException) cause;
System.out.println("Python exception type: " + pyEx.type);
System.out.println("Python exception value: " + pyEx.value);
}
}ScriptEngineFactory factory = new PyScriptEngineFactory();
// Get engine information
System.out.println("Engine Name: " + factory.getEngineName());
System.out.println("Engine Version: " + factory.getEngineVersion());
System.out.println("Language Name: " + factory.getLanguageName());
System.out.println("Language Version: " + factory.getLanguageVersion());
System.out.println("Extensions: " + factory.getExtensions());
System.out.println("MIME Types: " + factory.getMimeTypes());
System.out.println("Names: " + factory.getNames());
// Check specific parameters
Object threadingType = factory.getParameter(ScriptEngine.THREADING);
System.out.println("Threading: " + threadingType);ScriptEngine engine = manager.getEngineByName("python");
// Get default context
ScriptContext defaultContext = engine.getContext();
// Create isolated context for sensitive operations
ScriptContext isolatedContext = new SimpleScriptContext();
Bindings isolatedBindings = engine.createBindings();
isolatedBindings.put("secure_data", "sensitive information");
isolatedContext.setBindings(isolatedBindings, ScriptContext.ENGINE_SCOPE);
// Execute in isolated context
engine.eval("result = len(secure_data)", isolatedContext);
Object result = isolatedContext.getAttribute("result");
// Original context remains unaffected
Object originalData = defaultContext.getAttribute("secure_data");
System.out.println("Original context has secure_data: " + (originalData != null));// Cache compiled scripts for reuse
Map<String, CompiledScript> scriptCache = new ConcurrentHashMap<>();
public Object executeScript(String script, Map<String, Object> variables)
throws ScriptException {
// Get or compile script
CompiledScript compiled = scriptCache.computeIfAbsent(script, s -> {
try {
return ((Compilable) engine).compile(s);
} catch (ScriptException e) {
throw new RuntimeException(e);
}
});
// Create context with variables
ScriptContext context = new SimpleScriptContext();
Bindings bindings = engine.createBindings();
bindings.putAll(variables);
context.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
// Execute compiled script
return compiled.eval(context);
}// Use try-with-resources for automatic cleanup
try (AutoCloseable engine = (AutoCloseable) manager.getEngineByName("python")) {
engine.eval("print('Script executed')");
// Engine automatically closed
}
// Manual resource management
ScriptEngine engine = manager.getEngineByName("python");
try {
engine.eval("print('Script executed')");
} finally {
if (engine instanceof AutoCloseable) {
((AutoCloseable) engine).close();
}
}@Component
public class JythonScriptService {
private final ScriptEngine engine;
public JythonScriptService() {
ScriptEngineManager manager = new ScriptEngineManager();
this.engine = manager.getEngineByName("python");
}
@PostConstruct
public void initialize() throws ScriptException {
// Load common Python modules
engine.eval("""
import json
import datetime
import re
def format_data(data):
return json.dumps(data, indent=2)
""");
}
public String processData(Map<String, Object> data) throws ScriptException {
engine.put("input_data", data);
return (String) engine.eval("format_data(input_data)");
}
}@WebServlet("/python-script")
public class PythonScriptServlet extends HttpServlet {
private ScriptEngine engine;
@Override
public void init() throws ServletException {
ScriptEngineManager manager = new ScriptEngineManager();
engine = manager.getEngineByName("python");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String script = request.getParameter("script");
try {
engine.put("request_params", request.getParameterMap());
Object result = engine.eval(script);
response.setContentType("application/json");
response.getWriter().write(result.toString());
} catch (ScriptException e) {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
response.getWriter().write("Script error: " + e.getMessage());
}
}
}Install with Tessl CLI
npx tessl i tessl/maven-org-python--jython-standalone