【问题标题】:How can I provide a pseudo file system for r.js?如何为 r.js 提供伪文件系统?
【发布时间】:2012-11-14 05:14:11
【问题描述】:

好的,所以r.js 可以在Rhino 上运行。太棒了。

做它需要做的事情。

在 rhino 上,它基本上使用 java.io.Filejava.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")

编写所需的三个模拟类没有问题,即用来代替java.io.Filejava.io.FileInputStreamjava.io.FileOutputStream 的类,

this 等一些问题的答案指向 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 解决沙盒等价物......我继续得到 ​​p>

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

即使我在调用前加上java.io.File = org.jszip.rhino.SandboxFile 的执行,也将我的沙盒实现映射到现在缺少的java.io.File

我什至可以考虑在编译之前对加载的r.js 文件使用搜索和替换...但我觉得必须有更好的方法。

有人有什么提示吗?

【问题讨论】:

    标签: java javascript requirejs sandbox rhino


    【解决方案1】:

    好的,经过大量实验,这似乎是这样做的方法:

    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.File 等处的原始类,但对于r.js 的要求,这就足够了,其他人应该可以将此技巧扩展到一般情况。

    【讨论】:

      猜你喜欢
      • 2013-01-01
      • 2022-08-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-13
      • 1970-01-01
      • 2011-06-07
      • 2013-05-22
      相关资源
      最近更新 更多