Wednesday, March 14, 2007

Structured data to GWT component with JSON

Keywords:
GWT JSON stuctured initialisation data

Problem:
In a previous post I described using the internationalisation Dictionary class to pass in initialisation data. But what if the data is more complex than key-value pairs? You could define a dictionary value as being a delimited (e.g. space or comma separated) list of tokens but is there an easier way of getting in basic structured data without writing your own parser?

Solution:
JavaScript Object Notation (JSON) is a ".. text-based, human-readable format for representing objects and other data structures" (definition from wikipedia - the article includes a good introduction with examples). GWT supports reading and producing data in this format via the com.google.gwt.json.client package. For data interchange I think your still better off using a GWT remote service and sending your beans to it (let GWT handle the encoding/decoding) but for the host page giving data to the component JSON comes into its own.

Step 1


In the host page, define a dictionary as before but the value (or values) is/are now JSON strings rather than plain strings. In this example I'm creating an array of objects, each object having a property "id" and optionally a property "label" (it's got to be on one line as far as I can tell for the dictionary to allow it):
showHide: "[{\"id\": \"A\", \"label\": \"see A detail?\"}, {\"id\": \"B\", \"label\": \"include B detail?\"}, {\"id\": \"C\"}]"

Step 2


In the GWT component, use the dictionary to get at the JSON string. Then use the JSONParser to convert this to a JSON instance - in this example a JSONArray of JSONObjects. For a JSONObject you can get at each of its properties like you would a map via the get(String key) method.
public void onModuleLoad() {
    Dictionary properties = Dictionary.getDictionary("ModuleProperties");
  
    String showHideConfigString = properties.get("showHide");
    JSONArray showHideConfigs = (JSONArray)JSONParser.parse(showHideConfigString);
    
    List panels = new ArrayList();
    for (int i = 0; i < showHideConfigs.size(); i++) {
        JSONObject config = (JSONObject)showHideConfigs.get(i);
        
        JSONString idValue = (JSONString) config.get("id");
        String id = idValue.stringValue();
        
        JSONString labelValue = (JSONString) config.get("label");
        String label = (labelValue == null)? "include?" : labelValue.stringValue();
        
        // ... now we can do stuff with the data
        ShowHidePanel showHidePanel = new ShowHidePanel(label, id);
        RootPanel.get(id).add(showHidePanel);
        panels.add(showHidePanel);
    }
    
    // ... etc


Notes:
Someone asked me via comments how would you handle request parameters ... it's up to you to make something that can process the request parameters (CGI, java servlet, ASP?) and write a host page containing the data from the request params for the GWT component to then have access to them.

For many this will be obvious, but I felt bad for not including their comment ... but I don't want questions on the blog. Hope that helps.

If the data is more complex/rich than what JSON allows, there's XML.

No comments: