Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Intercept field access of java objects in Rhino

Is it possible to intercept field (and method) access of Java objects in the executed JavaScript code? Just like the delegate in JSCocoa that allows to handle property and method access.

like image 372
Display name Avatar asked May 07 '12 13:05

Display name


1 Answers

You can use Context.setWrapFactory to specify how to wrap Java Objects. Here shows wrappers that prints field access and method call:

InterceptWrapFactory.java

import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.WrapFactory;
public class InterceptWrapFactory extends WrapFactory{
    @Override
    public Scriptable wrapAsJavaObject(Context cx, Scriptable scope,
            Object javaObject, Class<?> staticType) {
        return new InterceptNativeObject(scope, javaObject, staticType);
    }
}

InterceptNativeObject.java

import org.mozilla.javascript.NativeJavaMethod;
import org.mozilla.javascript.NativeJavaObject;
import org.mozilla.javascript.Scriptable;
public class InterceptNativeObject extends NativeJavaObject {
    @Override
    public Object get(String name, Scriptable start) {
        Object res = super.get(name, start);
        System.out.println("Field get name="+name+" result="+res);
        if (res instanceof NativeJavaMethod) {
            NativeJavaMethod method = (NativeJavaMethod) res;
            return new JavaMethodWrapper(method);
        }
        return res;
    }
    public InterceptNativeObject(Scriptable scope, Object javaObject,
            Class<?> staticType) {
        super(scope, javaObject, staticType);
    }
}

JavaMethodWrapper.java

import org.mozilla.javascript.Context;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.NativeJavaMethod;
import org.mozilla.javascript.Scriptable;

public class JavaMethodWrapper implements Function {
    NativeJavaMethod method;
    public JavaMethodWrapper(NativeJavaMethod method) {
        this.method = method;
    }
    public boolean hasInstance(Scriptable instance) {
        return method.hasInstance(instance);
    }
    public Object call(Context cx, Scriptable scope, Scriptable thisObj,
            Object[] args) {
        System.out.println("Call method: "+method);
        return method.call(cx, scope, thisObj, args);
    }
    public boolean has(int index, Scriptable start) {
        return method.has(index, start);
    }
    public Scriptable construct(Context cx, Scriptable scope, Object[] args) {
        return method.construct(cx, scope, args);
    }
    public void put(int index, Scriptable start, Object value) {
        method.put(index, start, value);
    }
    public void delete(int index) {
        method.delete(index);
    }
    public Scriptable createObject(Context cx, Scriptable scope) {
        return method.createObject(cx, scope);
    }
    public boolean has(String name, Scriptable start) {
        return method.has(name, start);
    }
    public void defineConst(String name, Scriptable start) {
        method.defineConst(name, start);
    }
    public void put(String name, Scriptable start, Object value) {
        method.put(name, start, value);
    }
    public void delete(String name) {
        method.delete(name);
    }
    public Scriptable getPrototype() {
        return method.getPrototype();
    }
    public void setPrototype(Scriptable m) {
        method.setPrototype(m);
    }
    public Scriptable getParentScope() {
        return method.getParentScope();
    }
    public void setParentScope(Scriptable m) {
        method.setParentScope(m);
    }
    public Object[] getIds() {
        return method.getIds();
    }
    public Object get(int index, Scriptable start) {
        return method.get(index, start);
    }
    public Object get(String name, Scriptable start) {
        return method.get(name, start);
    }
    public String getClassName() {
        return method.getClassName();
    }
    public Object getDefaultValue(Class<?> typeHint) {
        return method.getDefaultValue(typeHint);
    }
}

And this is a test code:

import java.util.Vector;

import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;


public class InterceptTest {
    public static void main(String[] args) {
        Context cx=Context.enter();
        cx.setWrapFactory(new InterceptWrapFactory());
        Scriptable root=cx.initStandardObjects();
        ScriptableObject.putProperty(root,"v", new Vector<String>());
        cx.evaluateString(root, "v.add('foo'); v.get(0)", "src", 1, null);
    }
}
like image 161
hoge1e3 Avatar answered Sep 22 '22 20:09

hoge1e3