【发布时间】:2014-02-04 18:34:00
【问题描述】:
我正在尝试通过 JSNI 调用 parallels.js。 Parallels 为 web worker 提供了一个很好的 API,我编写了一些轻量级的包装代码,它为 GWT 的 worker 提供了比 Elemental 更方便的接口。但是我遇到了一个让我难过的错误:
com.google.gwt.core.client.JavaScriptException: (DataCloneError) @io.mywrapper.workers.Parallel::runParallel([Ljava/lang/String;Lcom/google/gwt/core/client/JavaScriptObject;Lcom /google/gwt/core/client/JavaScriptObject;)([Java object: [Ljava.lang.String;@1922352522, JavaScript object(3006), JavaScript object(3008)]): 无法克隆对象。
这来自于托管模式:
在 com.google.gwt.dev.shell.ModuleSpaceOOPHM.doInvoke(ModuleSpaceOOPHM.java:136) 上的 com.google.gwt.dev.shell.BrowserChannelServer.invokeJavascript(BrowserChannelServer.java:249)。 gwt.dev.shell.ModuleSpace.invokeNative(ModuleSpace.java:571) 在 com.google.gwt.dev.shell.ModuleSpace.invokeNativeVoid(ModuleSpace.java:299) 在 com.google.gwt.dev.shell.JavaScriptHost。在 io.mywrapper.workers.Parallel.runParallel(Parallel.java) 处调用NativeVoid(JavaScriptHost.java:107)
这是我的代码:
创建工作者的示例客户端调用:
Workers.spawnWorker(new String[]{"hello"}, new Worker() {
@Override
public String[] work(String[] data) {
return data;
}
@Override
public void done(String[] data) {
int i = data.length;
}
});
提供通用接口的API:
public class Workers {
public static void spawnWorker(String[] data, Worker worker) {
Parallel.runParallel(data, workFunction(worker), callbackFunction(worker));
}
/**
* Create a reference to the work function.
*/
public static native JavaScriptObject workFunction(Worker worker) /*-{
return worker == null ? null : $entry(function(x) {
worker.@io.mywrapper.workers.Worker::work([Ljava/lang/String;)(x);
});
}-*/;
/**
* Create a reference to the done function.
*/
public static native JavaScriptObject callbackFunction(Worker worker) /*-{
return worker == null ? null : $entry(function(x) {
worker.@io.mywrapper.workers.Worker::done([Ljava/lang/String;)(x);
});
}-*/;
}
工人:
public interface Worker extends Serializable {
/**
* Called to perform the work.
* @param data
* @return
*/
public String[] work(String[] data);
/**
* Called with the result of the work.
* @param data
*/
public void done(String[] data);
}
最后是 Parallels 包装器:
public class Parallel {
/**
* @param data Data to be passed to the function
* @param work Function to perform the work, given the data
* @param callback Function to be called with result
* @return
*/
public static native void runParallel(String[] data, JavaScriptObject work, JavaScriptObject callback) /*-{
var p = new $wnd.Parallel(data);
p.spawn(work).then(callback);
}-*/;
}
这是什么原因造成的?
JSNI 文档说,关于数组:
opaque value that can only be passed back into Java code
这很简洁,但最终我的数组会被传递回 Java 代码,所以我认为这些都可以。
编辑 - 好的,错误的假设。这些数组尽管表面上只是被传递回 Java 代码,但却导致了错误(这很奇怪,因为 DataCloneError 上几乎没有 googleability。)将它们更改为 String 是可行的;但是,String 不足以满足我的需求。看起来对象面临与数组相同的问题;我在另一个 StackOverflow 线程中看到了 Thomas 对 JSArrayUtils 的引用,但我不知道如何用字符串数组调用它(它需要一个 JavaScriptObjects 数组作为非原始类型的输入,这对我没有好处。)有什么巧妙的办法吗?
EDIT 2 - 在我使用 String[] 的任何地方都改为使用 JSArrayString。新问题;这次没有堆栈跟踪,但在控制台中我收到错误:未捕获的 ReferenceError:__gwt_makeJavaInvoke 未定义。当我在开发人员工具中单击生成脚本的 url 时,我得到了这个 sn-p:
self.onmessage = function(e) {self.postMessage((function (){
try {
return __gwt_makeJavaInvoke(3)(null, 65626, jsFunction, this, arguments);
}
catch (e) {
throw e;
}
})(e.data))}
我看到 _gwt_makeJavaInvoke 是 JSNI 类的一部分;那为什么找不到呢?
【问题讨论】: