1

さて、r.jsはRhinoで実行できます。これは素晴らしいことです。

それがする必要があることをするために。

rhinoでは、基本的にを使用し、java.io.File必要なファイルシステムの変更を実現します。java.io.FileOutputStreamjava.io.FileInputStream

(背景:私はMavenベースのJava / Javascript開発者により良い開発体験を提供することに取り組んでいます。Mavenであるため、慣習の力と意見の力があります。進捗状況はjszip.orgで確認できます。)

だから私がやりたいのは、ディスク上の構造を魔法のように仮想ファイルシステムとして表示させることです。

したがって、ディスク上では次のような構造になります。

/
/module1/src/main/js/controllers/controller.js
/module2/src/main/js/models/model.js
/module3/src/main/js/views/view.js
/webapp/src/build/js/profile.js
/webapp/src/main/js/main.js
/webapp/src/main/webapp/index.html

は次の/webapp/src/build/js/profile.jsようになります。

({
    appDir: "src",
    baseUrl:".",
    dir: "target",
    optimize: "closure",
    modules:[
        {
            name:"main"
        }
    ]
})

そのような

  • r.jsが要求したとき、new File("src/main.js")私は実際にそれを与えますnew File("/webapp/src/main/js/main.js")

  • それが求められnew File("profile.js")たら私はそれを与えますnew File("/webapp/src/build/js/profile.js")

  • それが求められnew File("controllers/controller.js")たら私はそれを与えますnew File("/module1/src/main/js/controllers/controller.js")

  • それが求められnew File("target")たら、私はそれを与えますnew File("/webapp/target/webapp-1.0-SNAPSHOT")

必要な3つのモッククラス、つまり、、、の代わりに使用するクラスを記述しても問題ありjava.io.Fileませjava.io.FileInputStreamjava.io.FileOutputStream

このようないくつかの質問には、ClassShutterのようなものを指す回答があります。これは、次のように使用できることがわかります。

        context.setClassShutter(new ClassShutter() {
            public boolean visibleToScripts(String fullClassName) {
                if (File.class.getName().equals(fullClassName)) return false;
                if (FileOutputStream.class.getName().equals(fullClassName)) return false;
                if (FileInputStream.class.getName().equals(fullClassName)) return false;
                return true;
            }
        });

元の実装を非表示にします。

問題は、Rhinoにサンドボックス化された同等のものを解決させることです...私は取得し続けます

TypeError: [JavaPackage java.io.File] is not a function, it is object.

java.io.File = org.jszip.rhino.SandboxFile以前にmapを実行して呼び出しの前にプレフィックスを付けたとしても、サンドボックス化された実装は、現在欠落しているものよりも優先されますjava.io.File

r.jsコンパイルする直前に、ロードされたファイルに対して検索と置換を使用することを検討することもできます...しかし、もっと良い方法があるはずだと思います。

誰かヒントはありますか?

4

1 に答える 1

2

さて、多くの実験の後、これはこれを行う方法のようです:

Scriptable scope = context.newObject(global);
scope.setPrototype(global);
scope.setParentScope(null);

NativeJavaTopPackage $packages = (NativeJavaTopPackage) global.get("Packages");
NativeJavaPackage $java = (NativeJavaPackage) $packages.get("java");
NativeJavaPackage $java_io = (NativeJavaPackage) $java.get("io");

ProxyNativeJavaPackage proxy$java = new ProxyNativeJavaPackage($java);
ProxyNativeJavaPackage proxy$java_io = new ProxyNativeJavaPackage($java_io);
proxy$java_io.put("File", scope, get(scope, "Packages." + PseudoFile.class.getName()));
proxy$java_io.put("FileInputStream", scope,
        get(scope, "Packages." + PseudoFileInputStream.class.getName()));
proxy$java_io.put("FileOutputStream", scope,
        get(scope, "Packages." + PseudoFileOutputStream.class.getName()));
proxy$java.put("io", scope, proxy$java_io);
scope.put("java", scope, proxy$java);

ヘルパーメソッドがあります:

private static Object get(Scriptable scope, String name) {
    Scriptable cur = scope;
    for (String part : StringUtils.split(name, ".")) {
        Object next = cur.get(part, scope);
        if (next instanceof Scriptable) {
            cur = (Scriptable) next;
        } else {
            return null;
        }
    }
    return cur;
}

そして、どこProxyNativeJavaPackageにあるのようなものですか

public class ProxyNativeJavaPackage extends ScriptableObject implements Serializable {
    static final long serialVersionUID = 1L;

    protected final NativeJavaPackage delegate;
    private final Map<String, Object> mutations = new HashMap<String, Object>();

    public ProxyNativeJavaPackage(NativeJavaPackage delegate) {
        delegate.getClass();
        this.delegate = delegate;
    }

    @Override
    public String getClassName() {
        return delegate.getClassName();
    }

    @Override
    public boolean has(String id, Scriptable start) {
        return mutations.containsKey(id) ? mutations.get(id) != null : delegate.has(id, start);
    }

    @Override
    public boolean has(int index, Scriptable start) {
        return delegate.has(index, start);
    }

    @Override
    public void put(String id, Scriptable start, Object value) {
        mutations.put(id, value);
    }

    @Override
    public void put(int index, Scriptable start, Object value) {
        delegate.put(index, start, value);
    }

    @Override
    public Object get(String id, Scriptable start) {
        if (mutations.containsKey(id)) {
            return mutations.get(id);
        }
        return delegate.get(id, start);
    }

    @Override
    public Object get(int index, Scriptable start) {
        return delegate.get(index, start);
    }

    @Override
    public Object getDefaultValue(Class<?> ignored) {
        return toString();
    }

    @Override
    public String toString() {
        return delegate.toString();
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof ProxyNativeJavaPackage) {
            ProxyNativeJavaPackage that = (ProxyNativeJavaPackage) obj;
            return delegate.equals(that.delegate) && mutations.equals(that.mutations);
        }
        return false;
    }

    @Override
    public int hashCode() {
        return delegate.hashCode();
    }
}

それでも元のクラスはPackages.java.io.Fileetcのままですが、r.js要件についてはこれで十分であり、他の人がこのトリックを一般的なケースに拡張できるはずです。

于 2012-11-27T09:07:05.333 に答える