GWT cell widgets with overlay types issues

1.1k views Asked by At

I have taken the Cell Table example from google developer's guide and made the following changes:

  • Use overlays instead of Java POJOs
  • Use a EditTextCell to edit one column

For my surprise, when running the code the Cell Table is adding an extra property to the overlay objects pushed into it. They should look like:

{"name":"John", "address":"123 Fourth Road"} {"name":"Mary", "address":"222 Lancer Lane"}

But instead they look like:

{"name":"John", "address":"123 Fourth Road", "$H":1} {"name":"Mary", "address":"222 Lancer Lane", "$H":2}

Here is the modified code that demonstrates the issue:

import java.util.Arrays;
import java.util.List;

import com.google.gwt.cell.client.EditTextCell;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.TextColumn;
import com.google.gwt.user.client.ui.RootPanel;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class Overlay implements EntryPoint {

    private static class Contact extends JavaScriptObject {

        protected Contact() {}

        public static native Contact create(String name, String address) /*-{
            return {"name" : name , "address" : address};
        }-*/;
        public final native String getName() /*-{
            return this["name"];
        }-*/;   
        public final native void setName(String name) /*-{
            this["name"] = name;
        }-*/;
        public final native String getAddress() /*-{
            return this["address"];
        }-*/;   
        public final native void setAddress(String address) /*-{
            this["address"] = address;
        }-*/;
    }

    private static List<Contact> CONTACTS = Arrays.asList(
            Contact.create("John", "123 Fourth Road"),
            Contact.create("Mary", "222 Lancer Lane"));

    /**
     * This is the entry point method.
     */
    public void onModuleLoad() {

        CellTable<Contact> table = new CellTable<Contact>();
        // Create name column.
        Column<Contact, String> nameColumn = new Column<Contact, String>(new EditTextCell()) {
            public String getValue(Contact object) {
                return object.getName();
            }
        };
        // Create address column.
        TextColumn<Contact> addressColumn = new TextColumn<Contact>() {
            public String getValue(Contact contact) {
                return contact.getAddress();
            }
        };
        // Add the columns.
        table.addColumn(nameColumn, "Name");
        table.addColumn(addressColumn, "Address");      
        table.setRowCount(CONTACTS.size(), true);
        // Push the data into the widget.
        printList();
        table.setRowData(0, CONTACTS);      
        printList();        
        RootPanel.get().add(table);
    }

    private void printList() {
        for(Contact contact : CONTACTS) {
            GWT.log(new JSONObject(contact).toString());
        }
    }

}

I have checked that it is the editable column the one that causes the issue. If I remove it the table does not modify my overlays.

Anyway, this is a very weird behaviour. I don't feel it is safe to work with overlays if your widgets can add them unexpected properties.

Has anyone encountered this issue before or is this behaviour documented anywhere? Any hints to solve it?

Thanks a lot

2

There are 2 answers

1
Javier Ferrero On BEST ANSWER

The correct answer to this issue was posted in the GWT development forum (link):

The $H property comes from the implementation of JavaScriptObject#hashCode() (in com.google.gwt.cire.client.impl.Impl#getHashCode(Object)).

In your case, this is due to AbstractEditableCell maintaining a map of value keys to their "view data", and your use (I guess) of the default ProvidesKey implementation (SimpleProvidesKey) which directly returns the item.

So, when rendering, the EditTextCell calls getViewData, which looks up the key in the map (and thus needs the hashcode of the key, hence the call to hashCode), and the key is your JSO (hence the new $H property).

I believe that giving a ProvidesKey implementation (in you case, returning the name property for instance) to the Celltable would solve your issue.

1
Ilia Akhmadullin On

I doubt that CellTable can sneakily edit your JSONs. Check those overlays in Firebug/Chrome_Developer_Tools/... if they ok then most likely bug is in this line:

GWT.log(new JSONObject(contact).toString());

There are atleast two issues for JSONObject.toString: Passing List to/from JSNI works in web mode but fails in hosted mode & toString() and JSNI.
In second issue there is comment according to which you can try this:

GWT.log( (String) new JSONObject(contact) );