Java Reflection and Introspection example, Populating Dojo Filtering Selects.

Reflection and Introspection

Reflection and Introspection are advanced java topics often utilized when building Java Web frameworks.  New developers tend to find reflection concepts difficult to fully understand.  In this example I will show off a very basic example of reflection used to reduce boiler plate code for populating Dojo filtering selects. This also has the positive side affect of keeping the front end easy to understand and consistent. This will allow the dojo framework dijit’s properties of label to =”label” and value=”value”.

Creating a Dojo Filtering select programatically.

(Not using markup)
In this case we will generate the filtering select programmatically and attach it to a placeholder dom node that exists in a JSP file.  The key thing here is that a filtering select has both a value and label for each item it contains.  We will populate the filtering select using a Dojo Memory Store to hold the JSON data.

  1. First we create the filtering select and replace an existing dom node with it.
  2. We create a method that will make an ajax call to populate the memory store and then assign the store to the filtering select.
  3. In this case the method returns a promise such that we can chain other events to it.

This code will generate a filtering select and replace an existing dom node with the newly created dojo.form.filteringselect
*note this code exists within a dojo module so it is only partial source. We will call the module FilteringSelectSource.js

 var stateDropdown = new FilteringSelect({
        id: "states",
        // the text to appear in the filtering select dropdown that has no value
        placeHolder:"Select an Option",
        style : "width: 35em",
       	// the attribute the filtering select will use to auto complete the value
        searchAttr: "label",
        labelAttr: "label",
        // the attribute that will display in the dropdown
        itemLabel: 'label',
        // the attribute that will be recorded when a value is selected
        itemValue: 'value',
        // the name of the property that will be submitted with the form.
        name: "state",
        disabled: true
      }, dom.byId("IDofTheTargetDomNodeToReplaceGoesHere"));

Then we will create a dojo xhr (ajax) call to populate the filtering select above. *Note the code isn’t much but my comments are verbose.

   function populateStates() {
       // using the deferred as a promise for chaining events
           var aPromise = new Deferred();
               var stateDropdown = dijit.byId("states");
           // Creating an animation to let the user know the form is still loading.
           var standby = new Standby({target: domAttr.get(stateDropdown.domNode, 'id')});
           document.body.appendChild(standby.domNode);
           standby.startup();
           standby.show();
 
           // create the xhr ajax call to the server 
           xhr(populateStatesUrl, {
               handleAs: 'json',
                   query: {    country : "USA" }
             }).then(function(resp) {
             // if your using dojo 1.6 you may need to wrap this memory store in an object store.
             // this creates a new dojo memory store that will contain data from the json response 
             // and assignes it to the widget
               stateDropdown.set('store',new MemoryStore({
                               data: resp,
                               idProperty: "value"
               }));
           // let the user know we are finished populating the dropdown.
           standby.hide();
               // resolve the promise when we are finished populating the filtering select.  
               // This will chained method calls to execute.
           aPromise.resolve(true);
           });
           return aPromise;
       }

It might be helpful to understand what the JSON should look like that will be stored in the memory store.  Basically it just needs to be an array of object items with key value pairs.

[
    {
        "name": "Alabama",
        "abbreviation": "AL"
    },
    {
        "name": "Alaska",
        "label": "AK"
    },
    {
        "label": "American Samoa",
        "value": "AS"
    },
    {
        "label": "Arizona",
        "value": "AZ"
    },
    {
        "label": "Arkansas",
        "value": "AR"
    },
    {
        "label": "California",
        "value": "CA"
    },
    {
        "label": "Colorado",
        "value": "CO"
    },
    {
        "label": "Connecticut",
        "value": "CT"
    },
    {
        "label": "Delaware",
        "value": "DE"
    },
    {
        "label": "District Of Columbia",
        "value": "DC"
    },
    {
        "label": "Federated States Of Micronesia",
        "value": "FM"
    },
    {
        "label": "Florida",
        "value": "FL"
    },
    {
        "label": "Georgia",
        "value": "GA"
    },
    {
        "label": "Guam",
        "value": "GU"
    },
    {
        "label": "Hawaii",
        "value": "HI"
    },
    {
        "label": "Idaho",
        "value": "ID"
    },
    {
        "label": "Illinois",
        "value": "IL"
    },
    {
        "label": "Indiana",
        "value": "IN"
    },
    {
        "label": "Iowa",
        "value": "IA"
    },
    {
        "label": "Kansas",
        "value": "KS"
    },
    {
        "label": "Kentucky",
        "value": "KY"
    },
    {
        "label": "Louisiana",
        "value": "LA"
    },
    {
        "label": "Maine",
        "value": "ME"
    },
    {
        "label": "Marshall Islands",
        "value": "MH"
    },
    {
        "label": "Maryland",
        "value": "MD"
    },
    {
        "label": "Massachusetts",
        "value": "MA"
    },
    {
        "label": "Michigan",
        "value": "MI"
    },
    {
        "label": "Minnesota",
        "value": "MN"
    },
    {
        "label": "Mississippi",
        "value": "MS"
    },
    {
        "label": "Missouri",
        "value": "MO"
    },
    {
        "label": "Montana",
        "value": "MT"
    },
    {
        "label": "Nebraska",
        "value": "NE"
    },
    {
        "label": "Nevada",
        "value": "NV"
    },
    {
        "label": "New Hampshire",
        "value": "NH"
    },
    {
        "label": "New Jersey",
        "value": "NJ"
    },
    {
        "label": "New Mexico",
        "value": "NM"
    },
    {
        "label": "New York",
        "value": "NY"
    },
    {
        "label": "North Carolina",
        "value": "NC"
    },
    {
        "label": "North Dakota",
        "value": "ND"
    },
    {
        "label": "Northern Mariana Islands",
        "value": "MP"
    },
    {
        "label": "Ohio",
        "value": "OH"
    },
    {
        "label": "Oklahoma",
        "value": "OK"
    },
    {
        "label": "Oregon",
        "value": "OR"
    },
    {
        "label": "Palau",
        "value": "PW"
    },
    {
        "label": "Pennsylvania",
        "value": "PA"
    },
    {
        "label": "Puerto Rico",
        "value": "PR"
    },
    {
        "label": "Rhode Island",
        "value": "RI"
    },
    {
        "label": "South Carolina",
        "value": "SC"
    },
    {
        "label": "South Dakota",
        "value": "SD"
    },
    {
        "label": "Tennessee",
        "value": "TN"
    },
    {
        "label": "Texas",
        "value": "TX"
    },
    {
        "label": "Utah",
        "value": "UT"
    },
    {
        "label": "Vermont",
        "value": "VT"
    },
    {
        "label": "Virgin Islands",
        "value": "VI"
    },
    {
        "label": "Virginia",
        "value": "VA"
    },
    {
        "label": "Washington",
        "value": "WA"
    },
    {
        "label": "West Virginia",
        "value": "WV"
    },
    {
        "label": "Wisconsin",
        "value": "WI"
    },
    {
        "label": "Wyoming",
        "value": "WY"
    }
]

Onto the backend code. There’s many ways to create the required JSON data in the backend. I like Jackson and REST so we for this example assume those technologies are being used in a rest services to handle the front end’s ajax call. The object returned from the rest service will be converted to a JSON representation automatically for us. The Objects returned to populate dropdowns will be lists of labels and values.

In order to generate JSON like the example above, such an item in the list would look something like this.

Pretty simple right? The annoying thing is populating a list of these objects using properties from other POJOS. What we want to do is create something using reflection and introspection that will handle this conversion for us. So we will use generics and create an object that contains a list of objects that have “value” and “label” members. This object will generate it’s own list based on the type of list you pass in, and the member variables names you want to map to “value” and “label”.

Now onto the Java Reflection and Introspection and Generics. We will create a class of a generic class called DropDownListBean that contains a list of the DropDownItemBeans which hold the key value pairs. The constructor for this object will take in a list of any type, along with the names of the properties that we want to use to map the “value” and “label” to. The class will use reflection to create method calls and populate it’s own list of items with “value” and “label” members.
(its internal list of DropDownItemBeans).

The method call to create the DropDownBean would look something like this:

DropDownBean<State> stateDropDownBean = new DropDownBean<>(stateList, abbreviation, fullName);

Where the state objects in teh stateList (not shown) have member variables “private String abbreviation;”, and a getter methods “public String getAbbreviation()… “, as well as member variables “private String fullName;” and methods “public String getFullName()…” Basically any object that follows the JavaBean standards should work. (With the exception of boolean methods which start with ‘is’)

This allows us to create a list of objects that can be used to populate a Dojo MemoryStore in one line assuming the rest service would do the object to json conversion for you, and that the rest service returns DropDownBean.getDropDownItems();




2 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *