Friday, January 3, 2014

Flex: JSON Deserialization

JSON a much shorter and faster response as compared to XML. Therefore, although some third party api out there still gives you the option of returning the results in XML format, it also gives you the option of getting the results in JSON format too. So I'm just doing up a simple JSON Deserialization example. :D

Main Application Class - SimpleJSONDeserialize.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
      xmlns:s="library://ns.adobe.com/flex/spark" 
      xmlns:mx="library://ns.adobe.com/flex/mx">
 <fx:Declarations>
  <s:HTTPService url="http://maps.googleapis.com/maps/api/geocode/json" 
        method="GET" 
        concurrency="single" 
        useProxy="false" 
        id="httpService" 
        result="httpServiceResultEvent(event)" 
        fault="httpServiceFaultEvent(event)">
   <s:request xmlns="">
    <address>{txtInput.text}</address>
    <sensor>false</sensor>
   </s:request>
  </s:HTTPService>
 </fx:Declarations>
 <fx:Script>
  <![CDATA[
   import com.adobe.serialization.json.JSON;
   
   import model.MapResult;
   import model.MapServiceResult;
   
   import mx.collections.ArrayCollection;
   import mx.rpc.events.FaultEvent;
   import mx.rpc.events.ResultEvent;
   
   import org.osflash.vanilla.Vanilla;
   
   private var mapResult:MapServiceResult;
   
   [Bindable]
   private var resultCollection:ArrayCollection;
   
   //Upon clicking on the button, we will trigger the request
   protected function searchBtnClickHandler(event:MouseEvent):void
   {
    httpService.send();
   }
   
   //Upon making a successful request
   protected function httpServiceResultEvent(event:ResultEvent):void
   {
    //Converts the json result to a Object.
    var tempJSONObject:Object = JSON.decode(String(event.result));
    
    //Converts the Object into a Object of class type MapServiceResult
    mapResult = new Vanilla().extract(tempJSONObject, MapServiceResult);
    
    //Since we couldn't bind a Vector to a Datagrid directly,
    //we will just push the results to a ArrayCollection and
    //bind it to a DataGrid.
    resultCollection = new ArrayCollection();
    for each(var item:MapResult in mapResult.results)
    {
     resultCollection.addItem(item);
    }
    resultCollection.refresh();
   }
   
   //Upon making a failure request
   protected function httpServiceFaultEvent(event:FaultEvent):void
   {
   }
  ]]>
 </fx:Script>
 <s:VGroup width="100%" 
     height="100%" 
     verticalAlign="middle" 
     horizontalAlign="center">
  <s:Label text="Please enter an address:"/>
  <s:HGroup horizontalAlign="center">
   <s:TextInput id="txtInput"/>
   <s:Button label="Search Now!" 
       id="searchBtn" 
       click="searchBtnClickHandler(event)"/>
  </s:HGroup>
  <s:DataGrid dataProvider="{resultCollection}" 
     width="400" 
     height="300">
   <s:columns>
    <s:ArrayList>
     <s:GridColumn headerText="Formatted Address"
          dataField="formattedAddress"/>
    </s:ArrayList>
   </s:columns>
  </s:DataGrid>
 </s:VGroup>
</s:Application>

Model class for HttpServiceResults - MapServiceResult.as
package model
{
 public class MapServiceResult
 {
  public var status:String;
  private var _results: Vector.;

  public function get results():Vector.
  {
   return _results;
  }

  /**
   * Vanilla class will handle all these mapping, hence
   * it will map the object results into the Vector
   * of type MapResult.
   * 
   * But when we are getting a empty string rather than
   * an Array, we will have to handle such a condition 
   */
  public function set results(value:*):void
  {
   _results = new Vector.;
   if(String(value) != "")
   {
    _results = value; 
   }
  }
 }
}

Model class for individual Result - MapResult.as
package model
{
 public class MapResult
 {
  //Vanilla will map all the values of 
  //address_components into the Vector 
  //addrComponents.
  [Marshall (field="address_components")]
  public var addrComponents: Vector.;
  [Marshall (field="formatted_address")]
  public var formattedAddress:String;
  public var types: Vector.;
 }
}

Model class for individual address_components - AddrComponents.as
package model
{
 public class AddrComponents
 {
  //Vanilla will map the value of the field 
  //long_name to longName 
  [Marshall (field="long_name")]
  public var longName:String;
  [Marshall (field="short_name")]
  public var shortName:String;
  public var types: Vector.;
 }
}
* Click here for the source files for the demo.
  (This requires a valid Google Geocoding API key, but currently it will work if you
  are running it locally.)
^ Click here to find out more about the Vanilla as3 library.
~ Click here to find out more about the as3corelib.

No comments:

Post a Comment