6

是否可以在执行的 JavaScript 代码中拦截 Java 对象的字段(和方法)访问?就像 JSCocoa 中允许处理属性和方法访问的委托一样。

4

2 回答 2

5

您可以使用 Context.setWrapFactory 来指定如何包装 Java 对象。这里显示了打印字段访问和方法调用的包装器:

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);
    }
}

拦截NativeObject.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);
    }
}

这是一个测试代码:

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);
    }
}
于 2012-05-11T14:49:27.570 回答
0

作为 hog1e3 建议的替代方案,还可以实现 Scriptable 接口来拦截对类的方法/字段的调用。

于 2012-05-16T07:16:00.197 回答