GWT/JSNI - "DataCloneError - An object could not be cloned"- 如何调试?

标签 gwt jsni

我正在尝试通过 JSNI 调用 parallels.js。 Parallels 围绕 Web Workers 提供了一个很好的 API,我编写了一些轻量级包装器代码,为 GWT 的 Workers 提供了比 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 对象: [Ljava.lang.String;@1922352522, JavaScript 对象(3006), JavaScript 对象(3008)]): 无法克隆对象。

这来自托管模式:

在 com.google.gwt.dev.shell.BrowserChannelServer.invokeJavascript(BrowserChannelServer.java:249) 在 com.google.gwt.dev.shell.ModuleSpaceOOPHM.doInvoke(ModuleSpaceOOPHM.java:136) 在 com.google。 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;
        }
    });

提供通用接口(interface)的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) {
            <a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="9cebf3eef7f9eeb2dcf5f3b2f1e5ebeefdececf9eeb2ebf3eef7f9eeefb2cbf3eef7f9ee" rel="noreferrer noopener nofollow">[email protected]</a>::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) {
            <a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="e3948c91888691cda38a8ccd8e9a94918293938691cd948c9188869190cdb48c91888691" rel="noreferrer noopener nofollow">[email protected]</a>::done([Ljava/lang/String;)(x);
        });
    }-*/;        
}

worker :

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 代码,但这些数组却导致了错误(这很奇怪,因为在 Google 上几乎没有关于 DataCloneError 的信息。)将它们更改为 String 是可行的;但是,String 不足以满足我的需求。看起来对象面临着与数组相同的问题;我在另一个 StackOverflow 线程中看到 Thomas 对 JSArrayUtils 的引用,但我不知道如何使用字符串数组调用它(它需要一个 JavaScriptObjects 数组作为非原始类型的输入,这对我没有好处。)有什么巧妙的方法可以解决这个问题吗?

编辑 2 - 在我使用 String[] 的地方更改为使用 JSArrayString。新问题;这次没有堆栈跟踪,但在控制台中出现错误:Uncaught ReferenceError:未定义 __gwt_makeJavaInvoke。当我单击开发人员工具中生成的脚本的 url 时,我得到以下代码片段:

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 类的一部分;那么为什么找不到呢?

最佳答案

您可以在这里找到 GWT 和 WebWorkers 的工作示例:https://github.com/tomekziel/gwtwwlinker/

这是一项初步工作,但使用此模式,我能够使用 AutoBeanFactory 提供的序列化将 GWT 对象传递给 Webworker 或从 Webworker 传递 GWT 对象。

关于GWT/JSNI - "DataCloneError - An object could not be cloned"- 如何调试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21538047/

相关文章:

javascript - MGWT ScrollPanel.scrollTo(0, y) 导致无法读取未定义的属性 'style'

javascript - 来自 JSNI 的外部函数调用不起作用

java - 如何从手写 JavaScript 调用 GWT 实例对象的 java 方法?

java - GWT DataGrid 标题,可过滤和排序

java - 运行 GWT 应用程序时出现 jreLeakPrevention.gcDaemonFail 错误

java - Activity 中的 GWT Rest 回调始终为空/null

java - 从 JSNI 类创建 GWT jar

javascript - Firefox 中 javascript RegExp 的奇怪行为

java - GWT:单元测试/模拟 JSNI 方法的最佳实践?

java - 如何在 JSNI 中使用 GWT $entry 函数?