jsni - overlay types - js arrays Java API

1,693 views
Skip to first unread message

Sebastián Gurin

unread,
Dec 21, 2012, 2:39:34 PM12/21/12
to google-we...@googlegroups.com
Hi all. I'm porting some javascript libraries to GWT and in this thread I hope I can share and learn best ways of accessing Js native arrays from java language.

I try to add the minimun overhead so I'm using GWT's JsArray, JsArrayMixed, JsArrayString, etc for referencing arrays whenever I can. But this is not so friendly for a Java programmer accustomed to work with real java arryas (String[]) or with java.util.Collection API.

The first thing I thought of was convert js arrays to Java arrays. Unfortunately i didn't found a way of doing this without (linear overhead);

public static JsArrayNumber toJsArrayDouble(double[]a) {
    if(a==null)
        return null;
    JsArrayNumber jsa = (JsArrayNumber) JsArrayNumber.createArray();
    for (int i = 0; i < a.length; i++) {
        jsa.push(a[i]);
    }
    return jsa;
}

Now I'm experimenting on wrapping a Js Array into a java Collection. For this I made a simple Java class that extends java.util.AbstractCollection [0] and wrapps a pure js array. So from jsni code now I can return Java Collections instead JsArray like types and the final user of my libs can write java statements like for(String s : myOverlay.getArrayProp()) {..}. 

Also this solution adds very few (constant) overhead. So now I'm using two getters for js arrays, one that return the real js array object using GWT's JsArray* and other that return a Java Collection:

/**
 * Returns 'columns' property (JavaScript array)
 * @return
 */
public native final JsArrayString columns() /*-{
    return this["columns"];
}-*/;
/**
 * Returns 'columns' property (Java Collection)
 * @return
 */
public native final Collection<String> getColumns() /*-{   
    return @org.sgx.test1.client.JsUtil::toJavaCollection(Lcom/google/gwt/core/client/JavaScriptObject;)(this["columns"]);
}-*/;


I would like to hear what others in the same situation do. Use JsArray* GWT's classes vs more Java friendly API ???  Thanks in advance any suggestion or comment is most appreciated.



[0] - Source code for my Java Collection class wrapper


import java.util.AbstractCollection;
import java.util.Iterator;
import com.google.gwt.core.client.JavaScriptObject;

/**
 * a Java Friendly way of working with Js Arrays using the Java.util.Collection API
 * @author sg
 *
 * @param <T>
 */
public class JsArrayCollection<T> extends  AbstractCollection<T> {

    private JsArr<T> _data;
    /**
     * creates an empty array
     */
    public JsArrayCollection() {
        _data = JsArr.create().cast();
    }
    /**
     * creates JsArrayCollection wrapping an existing js array
     */
    public JsArrayCollection(JavaScriptObject data) {
        this._data = data.cast();
    }
    public static <T> JsArrayCollection<T> create(JavaScriptObject data) {
        return new JsArrayCollection<T>(data);
    }


@Override
public Iterator<T> iterator() {
    return new JsArrayIterator<T>(this);
}

@Override
public int size() {
    return _data.size();
}


public static class JsArrayIterator<T> implements Iterator<T> {

    private JsArrayCollection<T> arr;
    int currentIndex;
    public JsArrayIterator(JsArrayCollection<T> arr) {
        this.arr = arr;
        currentIndex=0;
    }
   
    @Override
    public boolean hasNext() {
//        System.out.println(currentIndex+" - "+arr.size());
        return currentIndex < arr.size();
    }

    @Override
    public T next() {
        currentIndex++;
        return arr._data.get(currentIndex-1);
    }

    @Override
    public void remove() {
        arr._data.slice(currentIndex-1, currentIndex);
    }
   
}

/** untyped array */
private static class JsArr<T> extends JavaScriptObject {
protected JsArr(){}
public native final JsArr<T> slice(int start, int end)/*-{
    return this.slice(start, end);
}-*/;
public static final native <T> JsArr<T> create() /*-{
    return [];
}-*/;
public final native int size() /*-{
    return this.length;
}-*/;
public final native T get(int i) /*-{
return this[i];
}-*/;
}


}

Thomas Broyer

unread,
Dec 21, 2012, 10:59:47 PM12/21/12
to google-we...@googlegroups.com


On Friday, December 21, 2012 8:39:34 PM UTC+1, Sebastián Gurin wrote:
Hi all. I'm porting some javascript libraries to GWT and in this thread I hope I can share and learn best ways of accessing Js native arrays from java language.

I try to add the minimun overhead so I'm using GWT's JsArray, JsArrayMixed, JsArrayString, etc for referencing arrays whenever I can. But this is not so friendly for a Java programmer accustomed to work with real java arryas (String[]) or with java.util.Collection API.

The first thing I thought of was convert js arrays to Java arrays. Unfortunately i didn't found a way of doing this without (linear overhead);

public static JsArrayNumber toJsArrayDouble(double[]a) {

There's http://google-web-toolkit.googlecode.com/svn/javadoc/latest/com/google/gwt/core/client/JsArrayUtils.html for that, but it comes with restrictions on what you're allowed to do with the returned value.

That reverse operation allows using a for loop to iterate on a JsArray*, e.g.: for (double : toArray(myJsArrayNumber)) { … }

Now I'm experimenting on wrapping a Js Array into a java Collection. For this I made a simple Java class that extends java.util.AbstractCollection [0] and wrapps a pure js array. So from jsni code now I can return Java Collections instead JsArray like types and the final user of my libs can write java statements like for(String s : myOverlay.getArrayProp()) {..}. 

Also this solution adds very few (constant) overhead. So now I'm using two getters for js arrays, one that return the real js array object using GWT's JsArray* and other that return a Java Collection:

/**
 * Returns 'columns' property (JavaScript array)
 * @return
 */
public native final JsArrayString columns() /*-{
    return this["columns"];
}-*/;
/**
 * Returns 'columns' property (Java Collection)
 * @return
 */
public native final Collection<String> getColumns() /*-{   
    return @org.sgx.test1.client.JsUtil::toJavaCollection(Lcom/google/gwt/core/client/JavaScriptObject;)(this["columns"]);
}-*/;

FYI, I would have written it:

public final Collection<String> getColumns() {
   return JsUtils.toJavaCollection(columns());
}

I would like to hear what others in the same situation do. Use JsArray* GWT's classes vs more Java friendly API ???  Thanks in advance any suggestion or comment is most appreciated. 



[0] - Source code for my Java Collection class wrapper


import java.util.AbstractCollection;
import java.util.Iterator;
import com.google.gwt.core.client.JavaScriptObject;

/**
 * a Java Friendly way of working with Js Arrays using the Java.util.Collection API
 * @author sg
 *
 * @param <T>
 */
public class JsArrayCollection<T> extends  AbstractCollection<T> {

Maybe we should have something like that in GWT proper. There hasn't been much demand AFAICT, and if we start going that way, people will likely ask for java.util.List rather than java.util.Collection.

Sebastián Gurin

unread,
Dec 23, 2012, 9:22:11 PM12/23/12
to google-we...@googlegroups.com
Thank you Thomas for your reply, I learned new things. Didn't know about

if ( GWT.isScript() ) {you can cast the js array to java arrays directly }.

I will definetly use those classes for my projects. Thanks again

Message has been deleted

Greg

unread,
Sep 27, 2013, 12:48:21 PM9/27/13
to google-we...@googlegroups.com
This will NOT work in GWT > 2.2


Workaround provided there works.

Sebastián Gurin

unread,
Nov 18, 2013, 5:42:45 PM11/18/13
to google-we...@googlegroups.com
Thanks! fortunately I didn't get to use it in my projects but I will do it. GWT should provide with an official library or class for doing native stuff like this. People porting/wrapping javascript libraries to GWT really need a good utility class mainly for converting & casting java to JavaScript types and viceversa and are doing it by their own (my work: http://code.google.com/p/gwtjsutil/).... :(
Reply all
Reply to author
Forward
0 new messages