完成它需要做的事情。
在rhino上,它基本上使用java.io.File
,java.io.FileOutputStream
和java.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.File
,java.io.FileInputStream
和java.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解决沙盒等效问题......我一直在
TypeError: [JavaPackage java.io.File] is not a function, it is object.
即使我先前执行了java.io.File = org.jszip.rhino.SandboxFile
我的沙盒实施,而不是现在缺少的java.io.File
我甚至可以考虑在编译之前在加载的r.js
文件上使用搜索和替换...但我觉得必须有更好的方法。
有没有人有任何提示?
答案 0 :(得分: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.File
等,但对于r.js
要求,这已足够,其他人应该可以将此技巧扩展到一般情况。