在 GWT 中从 JsArray<JavaScriptObject> 转换为 List<JSONObject>

Posted

技术标签:

【中文标题】在 GWT 中从 JsArray<JavaScriptObject> 转换为 List<JSONObject>【英文标题】:Converting from JsArray<JavaScriptObject> to List<JSONObject> in GWT 【发布时间】:2010-06-26 18:44:59 【问题描述】:

在 GWT 中,我的代码中有一个 JsArray。它或多或少是一个 JSON 对象列表,但它的类型是 JsArray。它基本上必须采用这种格式,因为我使用 JSNI 将它作为参数传递给一些外部 javascript 代码。麻烦的是,我还希望 Java 代码使用这个值。在 Java 中,我更喜欢处理 List 类型的对象。不过,我还没有真正找到在这两件事之间进行转换的好方法。我能做的最好的事情是线性遍历数组以构建我想要的新类型:

  public List<JSONObject> getData() 
   LinkedList<JSONObject> list = new LinkedList<JSONObject>();
   for (int i = 0; i < data.length(); ++i) 
    list.add(new JSONObject(data.get(i)));
   
   return list;
  

我真的很倒霉吗?或者有没有一种快速的方法可以在这两种类型之间进行转换?

(返回值的 JSONArray 可能也可以...但是实现 List 接口的东西很好)。

【问题讨论】:

【参考方案1】:

之所以不能轻易地将JsArray 转换为List 接口的任何Java 实现,是因为JsArray 只是一个好的ol' JavaScript 数组的包装器。这允许对其进行一些非常快速的操作(因为 JSON 是 JS 的一部分),但代价是与“Java”代码的其余部分不“兼容”。所以你必须问问自己,速度是否是一个重要因素,如果你转换为“Java”列表(当然,在内部只是一个 JS 数组),你会损失多少。

AFAIR,我还没有找到任何优雅的解决方案来解决这种情况 - 但就我而言,我立即使用 JsArray 对象来创建 POJO 并进一步传递它们。

【讨论】:

【参考方案2】:

我们围绕 JsArray 实现了一个简单的包装器,只支持几个方法。如果您不需要 List 的所有功能:

public class JsArrayList<T> implements List<T> 

    private final JsArray<? extends T>  array;

    public JsArrayList(final JsArray<? extends T> array) 
        this.array = array;
    

    public boolean add(final T e) 
        throw new RuntimeException("Not implemented.");
    

    public boolean isEmpty() 
        return this.size() == 0;
    

    public Iterator<T> iterator() 
        if (array == null) 
        return new EmptyIterator<T>();
     else 
        return new JsArrayIterator<T>(array);
    
    

    public int size() 
        if (array == null) return 0;
        return array.length();
    

    public T get(final int index) 
        if (array == null)  throw new IndexOutOfBoundsException("array is emtpy"); 
        return array.get(index);
    

    ...

这是我们找到的最高效、最优雅的解决方案。

【讨论】:

你能分享完整的实现吗?谢谢! 类的其余部分与我发布的截图几乎相同。这个答案太长了。【参考方案3】:

根据@EduardWirch 的包装类想法,我创建了JsList,它使用JsArray 的扩展版本来处理大部分代码,您可以在JsList 获得它。它允许像这样通过 JsArrayExtend 创建 JsList:

public class Values extends JavaScriptObject

    protected Values ();
    static public final native JsArrayExtend getValues(String json) /*-return eval('('+json+')');-*/;


public class Value extends JavaScriptObject

    protected Value ()

    public final native String getName() /*-return this.name;-*/;


...

JsList<Value> valueList=JsList<Value>(Values.getList(jsonString));

这可以提供给任何采用 List 并且似乎工作正常的对象。我没有彻底测试过,如果你发现任何问题,请告诉我,我会更新它。

原来我创建了一个 JavaScriptObject 类型,它使用本机代码来充当列表,您可以在此处看到 JsList extends JavaScriptObject,但是它破坏了 GWT 类型系统,虽然它适用于 Javascript 编译,但它在其他情况下不起作用。

【讨论】:

【参考方案4】:

Turbo GWT Core 为其提供了优雅的解决方案。在它的 Js.Collections 包中,有 JsArrayList,一个包装原生 JS 数组的 List 实现。合同的许多方法都经过测试并按预期工作。此外,它适用于任何类型的 Object,而不仅仅是 Overlay 类型。

你可以像List myList = new JsArrayList(jsArray)一样直接包装一个JsArray。

Turbo GWT Js.Collections 还提供了自己的 JsArray 实现,具有更多方法并支持任何对象。还有一个 JsArrayIterator,也用于迭代 JsArrays。

您可以在https://github.com/growbit/turbogwt-core 找到更多信息。

【讨论】:

以上是关于在 GWT 中从 JsArray<JavaScriptObject> 转换为 List<JSONObject>的主要内容,如果未能解决你的问题,请参考以下文章

在 GWT 中从服务器向客户端发送文件

GWT 将大量数据从服务器发送到客户端的最佳实践

软件架构分解LinkedIn日志系统GWT HTML5支持——架构周报

Play Framework 2.4.1:如何从 JsArray 中移除元素

JSArray.prototype.find()

播放Framework和Scala Json,解析包含JSArray和JSObject的json