使用带类型响应的JsonpRequestBuilder抛出InCompatibleClassChangeError问题
这个错误java.lang.IncompatibleClassChangeError: Found interface com.google.gwt.cor.client.JsArray, but class was expected有两个核心原因,结合你的代码来看,我们一步步排查解决:
1. 先修正明显的包名拼写错误
错误信息里的com.google.gwt.cor.client.JsArray是拼写错误,正确的包名应该是com.google.gwt.core.client.JsArray。先检查你的代码导入语句,确保没有写错这个包名——这是最容易忽略的低级错误,却会导致奇怪的类型不匹配。
2. 理解GWT中JsArray的本质:它是接口,不是类
GWT的JsArray<T>本身就是一个接口,不是可实例化的类。你的代码中直接将JSONP响应映射到AsyncCallback<JsArray<SuggestedProduct>>,在某些GWT版本(尤其是2.8+)中会因为类型转换逻辑的变化抛出这个异常。正确的做法是通过native方法安全地转换响应对象:
修正步骤:
第一步:修改回调的返回类型为JavaScriptObject
把requestObject的回调类型改成AsyncCallback<JavaScriptObject>,避免直接使用JsArray作为泛型参数:
builder.requestObject(buildSuggestedProductURL(), new AsyncCallback<JavaScriptObject>() { public void onFailure(Throwable caught) { // 错误处理逻辑不变 } public void onSuccess(JavaScriptObject data) { if (data == null) { // 空数据处理逻辑不变 return; } // 用native方法将原始JS对象转换为产品数组 JsArray<SuggestedProduct> products = castToProductArray(data); // 后续渲染逻辑不变 SafeHtmlBuilder sb = new SafeHtmlBuilder(); sb.appendHtmlConstant("<h4>Suggested Products:</h4>"); for (int i=0; i < products.length(); i++) { SuggestedProduct product = products.get(i); // ... 你的渲染代码 } view.getSuggestedProducts().setInnerSafeHtml(sb.toSafeHtml()); } });
第二步:添加native转换方法
在你的类中添加一个native方法,负责将原始JavaScript对象转换为JsArray<SuggestedProduct>:
private native JsArray<SuggestedProduct> castToProductArray(JavaScriptObject obj) /*-{ return obj; }-*/;
这个方法利用GWT的JSNI(JavaScript Native Interface)直接在JS层面做类型转换,绕过Java层面的类型检查限制,这是GWT处理JS对象数组的标准做法。
3. 验证SuggestedProduct类的正确性
确保你的SuggestedProduct类完全符合GWT JavaScriptObject的要求:
- 必须是
JavaScriptObject的子类 - 构造方法必须是
protected且无参 - Native方法的签名必须正确(你的代码里的
getFormName()和getImageURL()是正确的,注意末尾的分号不能少)
额外建议:考虑使用JsArrayOf替代JsArray
在较新的GWT版本中,JsArrayOf<T>是更推荐的类型化数组处理方式,它提供了更类型安全的API。你可以把JsArray<SuggestedProduct>替换为JsArrayOf<SuggestedProduct>,对应的native转换方法也改成返回JsArrayOf<SuggestedProduct>即可。
内容的提问来源于stack exchange,提问作者Miniversal

