CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-mozilla--rhino

JavaScript engine implementation that enables JavaScript execution within Java applications with full ECMAScript support and Java-JavaScript interoperability.

Pending
Overview
Eval results
Files

java-integration.mddocs/

Java Integration

Comprehensive Java-JavaScript interoperability system providing seamless bidirectional communication, automatic type conversion, Java class access, and adapter objects for implementing Java interfaces with JavaScript.

Capabilities

Type Conversion

Automatic conversion between Java and JavaScript values with comprehensive type mapping and coercion rules.

/**
 * Converts Java object to JavaScript representation
 * @param value Java object to convert
 * @param scope JavaScript scope for object creation
 * @return JavaScript representation of Java object
 */
public static Object javaToJS(Object value, Scriptable scope);

/**
 * Converts Java object to JavaScript representation with explicit Context
 * @param value Java object to convert
 * @param scope JavaScript scope for object creation
 * @param cx Context for the conversion
 * @return JavaScript representation of Java object
 */
public static Object javaToJS(Object value, Scriptable scope, Context cx);

/**
 * Converts JavaScript value to Java object of specified type
 * @param value JavaScript value to convert
 * @param desiredType Target Java class/interface
 * @return Java object of desired type
 */
public static Object jsToJava(Object value, Class<?> desiredType);

/**
 * Converts JavaScript value to boolean
 * @param value JavaScript value
 * @return boolean representation
 */
public static boolean toBoolean(Object value);

/**
 * Converts JavaScript value to number
 * @param value JavaScript value
 * @return double representation
 */
public static double toNumber(Object value);

/**
 * Converts JavaScript value to string
 * @param value JavaScript value
 * @return String representation
 */
public static String toString(Object value);

/**
 * Converts JavaScript value to Scriptable object
 * @param value JavaScript value
 * @param scope Scope for object creation
 * @return Scriptable representation
 */
public static Scriptable toObject(Object value, Scriptable scope);

Usage Examples:

// Java to JavaScript conversion
List<String> javaList = Arrays.asList("a", "b", "c");
Object jsArray = Context.javaToJS(javaList, scope);

// JavaScript to Java conversion
String jsString = "42";
Object jsNumber = cx.evaluateString(scope, jsString, "test", 1, null);
Integer javaInt = (Integer) Context.jsToJava(jsNumber, Integer.class);

// Type coercion examples
Object jsValue = cx.evaluateString(scope, "true", "test", 1, null);
boolean javaBool = Context.toBoolean(jsValue);  // true
double javaNum = Context.toNumber(jsValue);     // 1.0
String javaStr = Context.toString(jsValue);     // "true"

// Converting JavaScript objects
Object jsObj = cx.evaluateString(scope, "({name: 'test', value: 42})", "test", 1, null);
Map<String, Object> javaMap = (Map<String, Object>) Context.jsToJava(jsObj, Map.class);

Java Object Wrapping

Wrapping Java objects for access from JavaScript with automatic method binding and property access.

/**
 * JavaScript wrapper for Java objects
 * Provides property access and method invocation from JavaScript
 */
public class NativeJavaObject extends ScriptableObject {
    /**
     * Creates wrapper for Java object
     * @param scope JavaScript scope
     * @param javaObject Java object to wrap
     * @param staticType Static type for method resolution
     */
    public NativeJavaObject(Scriptable scope, Object javaObject, Class<?> staticType);
    
    /**
     * Gets the wrapped Java object
     * @return Original Java object
     */
    public Object unwrap();
    
    /**
     * Gets the static type used for method resolution
     * @return Java class
     */
    public Class<?> getStaticType();
    
    /**
     * Coerces JavaScript value to Java type
     * @param type Target Java type
     * @param value JavaScript value to convert
     * @return Converted Java value
     */
    public static Object coerceTypeImpl(Class<?> type, Object value);
}

/**
 * JavaScript wrapper for Java classes (not instances)
 * Allows access to static methods and constructors
 */
public class NativeJavaClass extends NativeJavaObject {
    /**
     * Creates wrapper for Java class
     * @param scope JavaScript scope
     * @param cl Java class to wrap
     */
    public NativeJavaClass(Scriptable scope, Class<?> cl);
    
    /**
     * Gets the wrapped Java class
     * @return Java Class object
     */
    public Class<?> getClassObject();
}

/**
 * JavaScript wrapper for Java methods
 * Handles method overloading and parameter conversion
 */
public class NativeJavaMethod extends BaseFunction {
    /**
     * Creates wrapper for Java method(s)
     * @param methods Array of Method objects (for overloading)
     * @param name Method name for JavaScript
     */
    public NativeJavaMethod(Method[] methods, String name);
}

/**
 * JavaScript wrapper for Java constructors
 * Enables 'new' operator usage from JavaScript
 */
public class NativeJavaConstructor extends BaseFunction {
    /**
     * Creates wrapper for Java constructor(s)
     * @param constructors Array of Constructor objects
     */
    public NativeJavaConstructor(Constructor<?>[] constructors);
}

Usage Examples:

// Wrapping Java objects
StringBuilder sb = new StringBuilder("Hello");
Object wrappedSB = Context.javaToJS(sb, scope);

// Accessing from JavaScript
String result = (String) cx.evaluateString(scope, """
    wrappedSB.append(' World');
    wrappedSB.toString();
    """, "test", 1, null);
System.out.println(result);  // "Hello World"

// Working with Java classes
Class<?> stringClass = String.class;
Object wrappedClass = Context.javaToJS(stringClass, scope);
scope.put("StringClass", scope, wrappedClass);

// Using static methods from JavaScript  
Object staticResult = cx.evaluateString(scope, """
    StringClass.valueOf(123);
    """, "test", 1, null);

Java Array Integration

Special handling for Java arrays with JavaScript Array-like syntax and methods.

/**
 * JavaScript wrapper for Java arrays
 * Provides Array-like access and some Array prototype methods
 */
public class NativeJavaArray extends NativeJavaObject {
    /**
     * Creates wrapper for Java array
     * @param scope JavaScript scope
     * @param array Java array to wrap
     */
    public NativeJavaArray(Scriptable scope, Object array);
    
    /**
     * Gets array length
     * @return Array length
     */
    public int getLength();
    
    /**
     * Gets array element at index
     * @param index Array index
     * @return Array element
     */
    public Object get(int index);
    
    /**
     * Sets array element at index
     * @param index Array index
     * @param value New element value
     */
    public void put(int index, Object value);
}

Usage Examples:

// Working with Java arrays
int[] javaArray = {1, 2, 3, 4, 5};
Object wrappedArray = Context.javaToJS(javaArray, scope);
scope.put("javaArray", scope, wrappedArray);

// Access from JavaScript with array syntax
Object result = cx.evaluateString(scope, """
    javaArray[2] = 99;  // Modify Java array
    javaArray.length;   // Get length
    """, "test", 1, null);

// Java array is modified
System.out.println(Arrays.toString(javaArray));  // [1, 2, 99, 4, 5]

Java Collection Integration

Enhanced integration for Java Collection framework classes with JavaScript semantics.

/**
 * JavaScript wrapper for Java List implementations
 * Implements both Scriptable and List interfaces
 */
public class NativeJavaList extends NativeJavaObject implements List<Object> {
    /**
     * Creates wrapper for Java List
     * @param scope JavaScript scope
     * @param list Java List to wrap
     */
    public NativeJavaList(Scriptable scope, List<?> list);
    
    // List interface methods delegated to wrapped list
    public int size();
    public boolean isEmpty();
    public boolean contains(Object o);
    public Iterator<Object> iterator();
    public Object[] toArray();
    public boolean add(Object o);
    public boolean remove(Object o);
    public void clear();
    public Object get(int index);
    public Object set(int index, Object element);
    public void add(int index, Object element);
    public Object remove(int index);
}

/**
 * JavaScript wrapper for Java Map implementations
 * Provides Map access with JavaScript object semantics
 */
public class NativeJavaMap extends NativeJavaObject {
    /**
     * Creates wrapper for Java Map
     * @scope JavaScript scope
     * @param map Java Map to wrap
     */
    public NativeJavaMap(Scriptable scope, Map<?, ?> map);
    
    /**
     * Gets map size
     * @return Number of key-value pairs
     */
    public int size();
    
    /**
     * Checks if key exists
     * @param key Key to check
     * @return true if key exists
     */
    public boolean containsKey(Object key);
}

Usage Examples:

// Working with Java Collections
List<String> javaList = new ArrayList<>();
javaList.addAll(Arrays.asList("a", "b", "c"));
Object wrappedList = Context.javaToJS(javaList, scope);
scope.put("javaList", scope, wrappedList);

// Use from JavaScript with array-like syntax
cx.evaluateString(scope, """
    javaList[1] = 'modified';  // Set element
    javaList.add('d');         // Call List method
    """, "test", 1, null);

// Java List is modified  
System.out.println(javaList);  // [a, modified, c, d]

// Working with Maps
Map<String, Object> javaMap = new HashMap<>(); 
javaMap.put("key1", "value1");
Object wrappedMap = Context.javaToJS(javaMap, scope);
scope.put("javaMap", scope, wrappedMap);

// Access map from JavaScript
Object value = cx.evaluateString(scope, "javaMap.get('key1')", "test", 1, null);

Package and Class Access

Accessing Java packages and classes from JavaScript with automatic class loading.

/**
 * JavaScript representation of Java packages
 * Allows navigation of package hierarchy from JavaScript
 */
public class NativeJavaPackage extends ScriptableObject {
    /**
     * Creates package wrapper for given package name
     * @param packageName Java package name (e.g., "java.util")
     */
    public NativeJavaPackage(String packageName);
    
    /**
     * Gets package name
     * @return Package name string
     */
    public String getPackageName();
}

/**
 * Top-level package objects (java, javax, org, etc.)
 * Provides root access to Java package hierarchy
 */
public class NativeJavaTopPackage extends NativeJavaPackage {
    /**
     * Creates top-level package (java, javax, etc.)
     * @param packageName Top-level package name
     */
    public NativeJavaTopPackage(String packageName);
}

Usage Examples:

// Enable Java class access (done automatically with initStandardObjects)
ImporterTopLevel importerScope = new ImporterTopLevel(cx);

// Access Java classes from JavaScript  
Object result = cx.evaluateString(importerScope, """
    var ArrayList = java.util.ArrayList;
    var list = new ArrayList();
    list.add('item1');
    list.add('item2');
    list.size();
    """, "test", 1, null);
System.out.println(result);  // 2.0

// Import classes for easier use
cx.evaluateString(importerScope, """
    importClass(java.util.HashMap);
    var map = new HashMap();
    map.put('key', 'value');
    """, "test", 1, null);

WrapFactory

Controls how Java objects are wrapped for JavaScript access with customizable wrapping behavior.

/**
 * Factory for controlling Java object wrapping
 * Customize how Java objects appear in JavaScript
 */
public class WrapFactory {
    /**
     * Wraps Java object for JavaScript access
     * @param cx Current Context
     * @param scope JavaScript scope
     * @param obj Java object to wrap
     * @param staticType Static type for method resolution
     * @return Wrapped JavaScript object
     */
    public Object wrap(Context cx, Scriptable scope, Object obj, Class<?> staticType);
    
    /**
     * Wraps Java object as NativeJavaObject
     * @param cx Current Context
     * @param scope JavaScript scope
     * @param javaObject Java object to wrap
     * @param staticType Static type
     * @return NativeJavaObject wrapper
     */
    public Scriptable wrapAsJavaObject(Context cx, Scriptable scope, Object javaObject, Class<?> staticType);
    
    /**
     * Wraps Java class as NativeJavaClass
     * @param cx Current Context
     * @param scope JavaScript scope
     * @param javaClass Java class to wrap
     * @return NativeJavaClass wrapper
     */
    public Scriptable wrapJavaClass(Context cx, Scriptable scope, Class<?> javaClass);
    
    /**
     * Wraps new object (return value from constructor or method)
     * @param cx Current Context
     * @param scope JavaScript scope
     * @param obj New Java object
     * @param staticType Static type
     * @return Wrapped object
     */
    public Object wrapNewObject(Context cx, Scriptable scope, Object obj);
    
    /**
     * Checks if object should be wrapped
     * @param obj Java object
     * @param type Static type
     * @param isStatic true if static context
     * @return true if object should be wrapped
     */
    public boolean isJavaPrimitiveWrap();
}

Usage Examples:

// Custom WrapFactory to control wrapping behavior
WrapFactory customFactory = new WrapFactory() {
    @Override
    public Object wrap(Context cx, Scriptable scope, Object obj, Class<?> staticType) {
        // Custom wrapping logic
        if (obj instanceof MySpecialClass) {
            return new MySpecialWrapper(scope, obj, staticType);
        }
        return super.wrap(cx, scope, obj, staticType);
    }
};

// Set custom WrapFactory on Context
cx.setWrapFactory(customFactory);

// Now Java objects will be wrapped using custom logic
Object wrapped = Context.javaToJS(new MySpecialClass(), scope);

JavaAdapter

Creates Java objects that implement interfaces using JavaScript implementations.

/**
 * Creates Java objects implementing interfaces with JavaScript
 * Allows JavaScript functions to implement Java interfaces
 */
public class JavaAdapter {
    /**
     * Creates adapter object implementing Java interfaces
     * @param jsObj JavaScript object with method implementations
     * @param adapter Java interface/class to implement
     * @return Java object implementing interface
     */
    public static Object createAdapterWrapper(Scriptable jsObj, Object adapter);
    
    /**
     * Creates adapter class implementing interfaces
     * @param cx Current Context
     * @param scope JavaScript scope  
     * @param args Arguments: [interfaces..., constructor, prototype]
     * @param writeAdapter Whether to write class file
     * @return Constructor function for adapter class
     */
    public static Scriptable createAdapterClass(Context cx, Scriptable scope, Object[] args, boolean writeAdapter);
}

Usage Examples:

// Implementing Java interface with JavaScript
String jsCode = """
    new java.lang.Runnable({
        run: function() {
            print('Running from JavaScript!');
        }
    });
    """;

Object jsRunnable = cx.evaluateString(scope, jsCode, "adapter", 1, null);
Runnable runnable = (Runnable) Context.jsToJava(jsRunnable, Runnable.class);
runnable.run();  // Calls JavaScript function

// More complex interface implementation
String listenerCode = """
    new java.awt.event.ActionListener({
        actionPerformed: function(event) {
            print('Action performed: ' + event.getActionCommand());
        }
    });
    """;

Object jsListener = cx.evaluateString(scope, listenerCode, "listener", 1, null);
ActionListener listener = (ActionListener) Context.jsToJava(jsListener, ActionListener.class);

Advanced Integration Features

Method Overloading Resolution

Rhino automatically resolves Java method overloads based on argument types.

// Java class with overloaded methods
public class Calculator {
    public int add(int a, int b) { return a + b; }
    public double add(double a, double b) { return a + b; }
    public String add(String a, String b) { return a + b; }
}

// From JavaScript - automatic overload resolution
Calculator calc = new Calculator();
Object wrappedCalc = Context.javaToJS(calc, scope);
scope.put("calc", scope, wrappedCalc);

cx.evaluateString(scope, """
    calc.add(1, 2);        // Calls int version -> 3
    calc.add(1.5, 2.5);    // Calls double version -> 4.0  
    calc.add('a', 'b');    // Calls String version -> 'ab'
    """, "overload", 1, null);

Bean Property Access

Automatic property access for Java Bean getter/setter methods.

// Java Bean class
public class Person {
    private String name;
    private int age;
    
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
}

// From JavaScript - property-style access
Person person = new Person();
Object wrappedPerson = Context.javaToJS(person, scope);
scope.put("person", scope, wrappedPerson);

cx.evaluateString(scope, """
    person.name = 'John';   // Calls setName()
    person.age = 30;        // Calls setAge()
    
    var name = person.name; // Calls getName()
    var age = person.age;   // Calls getAge()
    """, "bean", 1, null);

Java Method Binding with FunctionObject

The FunctionObject class enables direct binding of Java methods and constructors to JavaScript functions with automatic type conversion.

/**
 * A JavaScript function object that wraps a Java method or constructor.
 * Enables binding Java methods to JavaScript functions with automatic
 * type conversion and proper 'this' handling.
 */
public class FunctionObject extends BaseFunction {
    /**
     * Create a JavaScript function object from a Java method or constructor.
     * @param name the name of the function
     * @param methodOrConstructor a java.lang.reflect.Method or Constructor
     * @param scope enclosing scope of function
     */
    public FunctionObject(String name, Member methodOrConstructor, Scriptable scope);
    
    /**
     * Return the arity (number of parameters) of the function.
     * @return the number of parameters
     */
    public int getArity();
    
    /**
     * Get the name of this function.
     * @return the function name, or empty string if none
     */
    public String getFunctionName();
    
    /**
     * Get the underlying Java method or constructor this function represents.
     * @return the Member (Method or Constructor)
     */
    public Member getMethodOrConstructor();
    
    /**
     * Define this function as a JavaScript constructor.
     * @param scope the scope to define the constructor in
     * @param prototype the prototype object
     */
    public void addAsConstructor(Scriptable scope, Scriptable prototype);
    
    // Type conversion utilities
    public static int getTypeTag(Class<?> type);
    public static Object convertArg(Context cx, Scriptable scope, Object arg, int typeTag);
    
    // Type constants for method parameter conversion
    public static final int JAVA_UNSUPPORTED_TYPE = 0;
    public static final int JAVA_STRING_TYPE = 1;
    public static final int JAVA_INT_TYPE = 2;
    public static final int JAVA_BOOLEAN_TYPE = 3;
    public static final int JAVA_DOUBLE_TYPE = 4;
    public static final int JAVA_SCRIPTABLE_TYPE = 5;
    public static final int JAVA_OBJECT_TYPE = 6;
}

Usage Examples:

// Bind static method to JavaScript function
public class MathUtils {
    public static double square(double x) {
        return x * x;
    }
    
    public static String format(String template, Object... args) {
        return String.format(template, args);
    }
}

// Create function binding
Method squareMethod = MathUtils.class.getMethod("square", double.class);
FunctionObject squareFunction = new FunctionObject("square", squareMethod, scope);
scope.put("square", scope, squareFunction);

// Use from JavaScript
Object result = cx.evaluateString(scope, "square(5)", "test", 1, null);
System.out.println(result); // 25.0

// Bind instance method to JavaScript function
public class Calculator {
    private double value = 0;
    
    public double add(double x) {
        return value += x;
    }
    
    public double getValue() {
        return value;
    }
}

Calculator calc = new Calculator();
Method addMethod = Calculator.class.getMethod("add", double.class);
FunctionObject addFunction = new FunctionObject("add", addMethod, scope);

// Bind the calculator instance
scope.put("calc", scope, Context.javaToJS(calc, scope));
scope.put("addToCalc", scope, addFunction);

// Use from JavaScript - the 'this' binding is handled automatically
cx.evaluateString(scope, "addToCalc.call(calc, 10)", "test", 1, null);
System.out.println(calc.getValue()); // 10.0

// Constructor binding
public class Point {
    private double x, y;
    
    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }
    
    public double getX() { return x; }
    public double getY() { return y; }
}

Constructor<Point> pointConstructor = Point.class.getConstructor(double.class, double.class);
FunctionObject pointFunction = new FunctionObject("Point", pointConstructor, scope);

// Add prototype for the constructor
Scriptable pointPrototype = cx.newObject(scope);
pointFunction.addAsConstructor(scope, pointPrototype);

// Use constructor from JavaScript
Object pointObj = cx.evaluateString(scope, "new Point(3, 4)", "test", 1, null);
// Creates a Point instance accessible from JavaScript

Exception Handling

Java exceptions are automatically converted to JavaScript errors.

// Java method that throws exception
public class TestClass {
    public void throwException() throws Exception {
        throw new IllegalArgumentException("Test exception");
    }
}

// From JavaScript - exception becomes JavaScript error
TestClass test = new TestClass();
scope.put("test", scope, Context.javaToJS(test, scope));

try {
    cx.evaluateString(scope, """
        try {
            test.throwException();
        } catch (e) {
            print('Caught: ' + e.message);  // "Test exception"
            print('Java class: ' + e.javaException.getClass().getName());
        }
        """, "exception", 1, null);
} catch (WrappedException we) {
    // WrappedException contains the original Java exception
    Throwable original = we.getWrappedException();
}

Install with Tessl CLI

npx tessl i tessl/maven-org-mozilla--rhino

docs

index.md

java-integration.md

javascript-objects.md

script-execution.md

security-debugging.md

tile.json