Showing posts with label groovy. Show all posts
Showing posts with label groovy. Show all posts

Wednesday, February 17, 2010

Groovy GPath for complex object traversal

GPath is a path expression language integrated into Groovy which allows parts of nested structured data to be identified and processed. GPath is named after popular XPath functionality to traverse XML nodes. GPath can be used to process XML nodes or composite objects.

class Person{
String firstName
String lastName
int age
}

def personList = [
new Person(firstName: "dhaval", lastName: "nagar", age: 25),
new Person(firstName: "nachiket", lastName: "patel", age: 24),
]

The easiest way to get all firstName from the above collection is to use collect{} closure:

println personList.collect{it.firstName}
// will print ["dhaval", "nachiket"]

But Groovy believes in shortening the most obvious stuff so the above statement can be rewritten like the following the still get the same result.

println personList.firstName

This feature becomes powerful when combined with Regular Expression. The following statement will print all the person whose first name starts with "d".

println personList.firstName.grep(~/d.*/)
// will print ["dhaval"]

However GPath is more popular to parse the XML documents effectively. Here we will take a small XML document and parse it with XmlSlurper and access it's nodes with GPath.

def mylinks = """
<links>
  <link>
    <id>1</id>
    <url>www.google.com</url>
  </link>
  <link>
    <id>2</id>
    <url>www.apple.co.in</url>
  </link>
</links>
"""

def links = new XmlSlurper().parseText(mylinks)

The following statement will print all the URL ending with "com"
println links.link.url.grep(~/.*com/)

The following statement will print all the URL ending with "co.in". One way to escape the . is to surround it with square brackets.
println links.link.url.grep(~/.*co[.]in/)

If my xml document changes radically, its affects my code very slightly.

def mylinks = """
<links>
  <link id="1" url="www.google.com"/>
  <link id="2" url="www.apple.co.in"/>
</links>    
"""

To find out urls ending with "com" and "co.in":

println links.link.@url.grep(~/.*com/)
println links.link.@url.grep(~/.*co[.]in/)

@ is the operator to access the property of a node. Parsing XML documents in such an easy way is a dream come true for a Java programmer.

Wednesday, February 10, 2010

Groovy Category and Dynamic Overriding

A Category class is an ordinary class which contains set of methods. The class can be used for a duration of code block and when used first parameter type of each method treats the declared method as its member method.

class TestCategory{
static def test(String str){
return "testing"
}
}

use(TestCategory){
// test() can be called as a member method inside the use block
assert "testing" == "a".test()
}

A category class can contain method without any parameters but it is not possible to use such method in the use block. A category class method should at least have one parameter to get called from the use block. The following code will throw an exception at the time of execution.

class EmptyMethodCategory{
static def emptyMethod(){
return "empty"
}
}

use(EmptyMethodCategory){
assert "empty" == emptyMethod()
}

Operator overriding is the most suitable use of the Category classes. In case of operator overriding, if the caller is not matching with any of the overridden methods, original method will be executed.

class StringSumCategory{
static def plus(String str1, String str2){
return str1.toInteger() + str2.toInteger()
}
}

use(StringSumCategory){
assert 3 == "1" + "2"
assert "12" == "1" + 2
}

If the category class contains a method with only one parameter of type Object, that method will be available to any possible type in Groovy.

class SerializeCategory{
static def serialize(Object obj){
// do serialization stuff
return serializedObj
}
}

use(SerializeCategory){
println 1.serialize()
println "a".serialize()
println ([1, 2, 3].serialize())
println this.serialize()
println serialize()
}

Groovy is full of surprises. It contains some of the best features from many static and dynamic languages.

Spread operator

Spread operator helps Groovy collections (list, range and map) to simple comma separated values. Spread operator is so flexible which can be used anywhere. For example:

def test(a, b, c){
return a + b + c
}

def numList = [1, 2, 3]

If you want to pass the above list of values to the test() method you have to write some boilerplate code to extract the elements and pass them in the method.

Whereas the spread operator is introduced to eliminate boilerplate code and follow clean coding. The above method can be called with the given list without a single extra line of code.

test(*numList)

An asterisk followed by list, range or map will spread the collection and convert all the containing values to comma separated values. The above example will work same for Range.

def numRange = 1..3
test(*numRange)

Map has different syntax compared to List and Range.

def aMap = [a:1, b:2]
def bMap = [c:3, *:aMap]

Likewise Groovy contains many such shortening facilities where development time can be reduces and code can remain clear and understandable.

Groovy spread-dot operator in GPath

GPath is an expression language integrated into Groovy to process nested objects. The dot and spread-dot operators helps to build the GPath expression. The dot operator is used to access the properties and spread-dot operator is used to access property, field or method.

class Person{
String firstName
String lastName
int age

int calc(){
return age * 2
}
}

def personList = [
new Person(firstName: "dhaval", lastName: "nagar", age: 25),
new Person(firstName: "nachiket", lastName: "patel", age: 24)
]

To access the firstName property one can use either of the operators:

println personList.firstName
// ["dhaval", "nachiket"]

println personList*.firstName
// ["dhaval", "nachiket"]

To access the calc() method spread-dot operator has to be used, whereas dot operator will raise an exception:

println personList*.total()
// [50, 48]

Apart from the access restrictions both the operators works differently when collection contains null values like:

personList << null
personList << new Person(firstName: "sandeep", lastName: "shah", age: 30)

println personList.firstName
// ["dhaval", "nachiket", "sandeep"]

println personList*.firstName
// ["dhaval", "nachiket", null, "sandeep"]

The spread-dot operator will add the null value for each null element in the resulting list.

Both the operators works same when the list element is not null but the requested property is null.

personList.clear()
personList << new Person(firstName: "dhaval", lastName: "nagar", age: 25)
personList << new Person(lastName: "nagar", age: 25)

println personList.firstName
// ["dhaval", null]

println personList*.firstName
// ["dhaval", null]

To avoid such null values in the resulting list, grep expression can be used.

println personList.grep{it?.firstName}.firstName
// ["dhaval"]

Here grep will try to evaluate the true boolean condition, as per the Groovy Truth if an object is NULL it will be considered as FALSE. So above expression will reject all the objects where firstName property value is null.

Tuesday, February 9, 2010

Calling Groovy closure from Java

After spending some time with Groovy alone i thought to mix Groovy code with Java. As closures seems the most weird in Groovy i tried to access a closure method from the Java class.

// Groovy code
class ClosureTest{
String firstName
String lastName

def proc(Closure closure){
closure.call(firstName, lastName)
}
}

// Groovy client
def ct = new ClosureTest()
ct.firstName = "dhaval"
ct.lastName = "nagar"
ct.proc{fn, ln -> println "$fn, $ln"}

// Java client

import groovy.lang.Closure;

class JavaClosureClient{
public static void main(String[] args){
ClosureTest ct = new ClosureTest();
ct.setFirstName("dhaval");
ct.setLastName("nagar");

ct.proc(new Closure(ct){
public Object call(Object[] argument){
System.out.println(argument[0] + ", " + argument[1]);
return null;
}
});
}
}

Well the difference shows the verbosity of the Java client compared to the Groovy one.

At my workplace we are not in a position to use Groovy extensively but with such silent integration between the two i am sure we can leverage some of the Groovy features.

Java Programmer's first look on Groovy

Like many Java programmers i started learning Groovy for some fascinated stuffs like Dynamic Typing, Closures, functional programming, etc. Overall the first experience with the Groovy was mind blowing. It has many new things to learn. To start with i am using Groovy in Action, its an excellent book for Groovy beginners.

My first encounter with Groovy started with the conventional "Hello World" program. The Hello World example finished and as such i didn't learn anything.

println "Hello, World"

But meanwhile i found that there are various ways to execute the above groovy code snippet:

1. From command prompt

>groovy -e "println 'Hello, World'"

2. From .groovy file

// HelloWorld.groovy

println "Hello, World"

// on prompt
// .groovy extension is optional
>groovy HelloWorld.groovy

3. From Groovy Interactive Console

// on prompt
>groovyConsole

A GUI application will open where in the upper half part developer can write the Groovy script and on lower half can see the script result.

4. From Groovy Shell

Though i haven't explored the Shell much but i could execute one line at a time and "Hello World" needs one line only. Following is the command to open the Groovy Shell:

// on prompt
>groovysh

Seemingly it would look quite simple to a new learner, but the real magic starts when the above code is either executed by Java interpreter or used by a Java program.

Convert Groovy files to .class files

// on prompt
// .groovy extension is NOT OPTIONAL this time
>groovyc HelloWorld.groovy

And the above command will create a .class file which can be executed with:

// on prompt
>java -classpath .;{groovy home}\embeddable\groovy-all-1.6.7.all.jar HelloWorld

And it works correctly. The same way this class file can be access by any Java program, it can create an instance or call the main() method directly.

So overall my first experience with Groovy was really good and i am quite sure to spend some time with this emerging language.

References

1. Groovy Home
3. Lots of links at Groovy DZone

Monday, February 8, 2010

Getting Started with Grails, Second Edition

The second edition of Getting started with Grails has just released. As the name says the book gives the step-by-step knowledge for the Grails framework and its fundamentals. The book is very well written and a must read for Grails beginners.

Scott Davis and Jason Rudolph both are very well known in Groovy and Grails world. The book will surely help you understand the power of Grails.

The book is available in the infoq.com bookshelf http://www.infoq.com/minibooks/grails-getting-started.

If you are a Groovy/Grails beginners like me, read Mastering Grails article series by Scott Davis at http://www.ibm.com/developerworks/views/java/libraryview.jsp?search_by=mastering+grails