Groovy #5 – Property reflection by map notation

Yet another nice feature of Groovy is the ability to access a member of an object instance using map notation. This may look like a syntactic sugar at first, but the sugar coat leads to a nice icing on the cake.

Consider a class

class KeyValuePair {
String name
String value
}

The usual notation to access the members would be k.name, k.value. But in Groovy, you can also do it like the following:

KeyValuePair k = new KeyValuePair()
k['name'] = 'searchSite'
k['value'] = 'http://www.google.com'

assert k.name == 'searchSite'
assert k.value == 'http://www.google.com'

So, whats the big deal? The big deal is, reflection made ridiculously easy. Note that ‘name’ is actually a string that evaluates to the member name of the class. Which means it can be a variable.

Consider a trivial ORM implementation – a csv file with a header-row which represent column names and the rows which represent values. How will you generically convert that csv file into an array of a specific object?

class CsvDb {
List data = new ArrayList()

public List load(String fileName, String className) {
FileReader fr = new FileReader(fileName)
String header = fr.readLine()
if (header == null) return data

List columns = header.tokenize(",")
String line
while ((line = fr.readLine()) != null) {
def object = Class.forName(className).newInstance()
List row = line.tokenize(",")
columns.eachWithIndex { col, index -> object[columns[index]] = row[index]?:"" }
data.add(object)
}

data
}
}

Look at line #14, columns.eachWithIndex {} closure, it sets the value of the given object’s property using map notation to the value of the row in the corresponding column.

Now given any csv formatted data and a class that has members matching the column names, the above snippet will generate a List of the given objects.

/** c:/data/flix.csv **/
actor,movie,genre
Ron Livingston,Office Space,Comedy
Joe Pesci,My Cousin Vinny,Comedy
Daniel Craig,Skyfall,Action
Jamie Bell,Tintin,Animation

and we want that mapped to an object called Flix.

package com.moviedb

class Flix {
String actor
String movie
String genre

static List flix

static void load() {
flix = new TextDb().load("c:/data/flix.csv", "com.moviedb.Flix")
}
}
Advertisements

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: