Converting from JsArray<JavaScriptObject> to List<JSONObject> in GWT
In GWT, I have a JsArray<JavaScriptObject> in my code. It's more or less a list of JSON objects, but its type is JsArray<JavaScriptObject>. It basically has to be in this format, because I pass it as a parameter to some external JavaScript code using JSNI. Trouble is, I also want this value to be used by Java code. In Java, I'd prefer to deal with an object of type List<JSONObject>. I haven't really found a good way to convert between these two things, though. The best I've been able to do is a linear walk through the array to build the new type I want:
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)));
}
r开发者_JS百科eturn list;
}
Am I horribly out of luck? Or is there a nice fast way to get between these two types?
(Returning a JSONArray of values would perhaps be OK as well... but something that implements the List interface is nice).
The reason why you can't easily cast JsArray
to any Java implementation of the List
interface is because JsArray
is just a wrapper around a good ol' JavaScript array. This allows for some very quick operations on it (since JSON is part of JS), but at the cost of not being "compatible" with the rest of the "Java" code. So you have to ask yourself if speed is an important factor and how much will you lose if you convert to a "Java" list (which, of course, internally will be just a JS array).
AFAIR, I haven't been able to find any elegant solution to this situation - but in my case I used the JsArray objects right away to create POJOs and pass those further.
We implemented a simple wrapper around JsArray
supporting just few methods. If you don't need all the List's functionality:
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);
}
...
}
This is the most performant and elegant solution we found.
Working from @EduardWirch idea of a wrapper class I created JsList which uses and extended version of JsArray, to handle most of the code natively, you can get it here JsList. It allows creating JsList via JsArrayExtend like so:
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));
This can be fed to any Object that takes List<> and seems to work fine. I have not thoroughly tested it so if you see any problems let me know and I will update it.
Original I created one of type JavaScriptObject that uses native code to act like a list you can see here JsList extends JavaScriptObject, however it breaks the GWT typing system and although it works for Javascript compiles it does not work otherwise.
Turbo GWT Core offers an elegant solution for it. Inside its Js.Collections package, there is JsArrayList, a List implementation wrapping native JS array. Many methods of the contract are tested and work as expected. Also, it works with any kind of Object, not only Overlay types.
You can wrap a JsArray directly like List myList = new JsArrayList(jsArray)
.
Turbo GWT Js.Collections also provides an own JsArray implementation with more methods and supporting any Object. There's a JsArrayIterator, for iterating over JsArrays too.
You can find more at https://github.com/growbit/turbogwt-core.
精彩评论