Я пытаюсь обратиться к parallels.js через JSNI. Parallels предоставляет хороший API для веб-работников, и я написал несколько облегченных оберток кода, который обеспечивает более удобный интерфейс для работников из GWT, чем Elemental. Однако я получаю сообщение об ошибке:GWT/JSNI - «DataCloneError - объект не может быть клонирован» - как мне отлаживать?
com.google.gwt.core.client.JavaScriptException: (DataCloneError) @ io.mywrapper.workers.Parallel :: runParallel ([Ljava/lang/String; (Объект Java: [Ljava.lang.String; @ 1922352522, объект JavaScript (3006), объект JavaScript (3008), объект Lcom/google/gwt/core/client/JavaScriptObject, Lcom/google/gwt/core/client/JavaScriptObject;)]): Объект не может быть клонирован.
Это происходит из, в режиме хоста:
в 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.invokeNativeVoid (JavaScriptHost.java:107) в io.mywrapper.workers.Parallel.runParallel (Parallel.java)
Вот мой код:
Пример клиентского вызова для создания рабочего:
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) {
[email protected]::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) {
[email protected]::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 код, поэтому я предполагаю, что они в порядке.
EDIT - хорошо, плохое предположение. Массивы, несмотря на то, что они якобы передаются обратно на Java-код, вызывают ошибку (что странно, потому что в DataCloneError очень мало googleability.) Изменение их на String работает; однако String для моих нужд недостаточно. Похоже, объекты сталкиваются с теми же проблемами, что и массивы; Я видел ссылку Томаса на JSArrayUtils в другом потоке StackOverflow, но я не могу понять, как вызвать его с помощью массива строк (он хочет, чтобы массив JavaScriptObjects был введен для не-примитивных типов, что не делает мне ничего хорошего). Есть ли опрятный выход из этого?
EDIT 2 - Изменен для использования JSArrayString везде, где я использовал String []. Новый выпуск; на этот раз нет stacktrace, но в консоли я получаю сообщение об ошибке: Uncaught ReferenceError: __gwt_makeJavaInvoke не определен. Когда я щелкаю по ссылке на сгенерированный сценарий в инструментах разработчика, я получаю этот фрагмент:
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; так почему бы его не найти?
Спасибо. Итак, законно создавать и заполнять JsArrayString в Java-коде? И я могу передать это как с Java на Javascript, так и обратно? – user717847
Да, это правильно - любой JSO (подкласс JavaScriptObject) может быть передан между Java/JSNI/JavaScript и использоваться так, как если бы он действительно был там. В объявлении (и создании экземпляров) JSOs допускаются только ограничения, они должны иметь защищенный ctor и создаваться только в JS/JSNI, все методы должны быть окончательными. О, и вы не можете называть методы JSO изнутри JSNI, хотя это редко вызывает беспокойство, поскольку вы можете назвать версии JS. Используйте 'JsArrayString array = JavaScriptObject.createArray(). Cast()' для его создания и java-look методы для заполнения. –
Спасибо, я приближаюсь. См. Мой «EDIT 2» выше; Я изменил свой код, чтобы использовать JSArrayString, где я ранее использовал String [], и теперь я получаю также ungoogleable «Uncaught ReferenceError: __gwt_makeJavaInvoke не определен». (Мне особенно не повезло или не так много людей делают это?) Любые идеи о том, что вызывает это? – user717847