Loading...

Thursday, July 15, 2010

Groovy Goodness: Use a Class by Proxy

In the groovy.util package we find the Proxy class. We can use this class to create a proxy for another object. All methods calls to the proxy object are redirected to the original object, instead for the methods we override in the proxy class:

class User {
    String name
    String email
    String password

    String displayName() { name }
}

class UserProxy extends groovy.util.Proxy {
    List fields

    // Override getProperty for custom behavior by the proxy.
    Object getProperty(String propertyName) {
        if (propertyName in fields) {
            getAdaptee().getProperty(propertyName)
        } else {
            throw new MissingPropertyException("Unknown property $propertyName")
        }
    }
}

def user = new User(name: 'mrhaki', email: 'private@localhost', password: 'secret')
def userProxy= new UserProxy(fields: ['name']).wrap(user)  // Create proxy for user instance.

assert 'mrhaki' == userProxy.name
try {
    userProxy.email
    assert false
} catch (MissingPropertyException e) {
    assert 'Unknown property email' == e.message
}
assert 'mrhaki' == userProxy.displayName()  // Use original method.

Groovy Goodness: Create Indexed Property Getter and Setter Methods

In Groovy we can define properties in our class and automatically the getter and setter methods for these properties are generated in the class file. If we have a Collection type property we normally get the get/set method for this property. But according to the JavaBean specification we can define a Collection type property as indexed property. This means we need an extra get/set method with an index parameter, so we can set the value of a element in the property directly:

//Methods to access individual values
public PropertyElement getPropertyName(int index)
public void setPropertyName(int index, PropertyElement element)

/Methods to access the entire indexed property array
public PropertyElement[] getPropertyName()
public void setPropertyName(PropertyElement element[])

Normally if we use our class in Groovy code we don't need those extra methods, because we can GPath to access and set elements in the Collection typed property. But suppose our class needs to be accessed from Java code or by an IDE, we want those extra methods. We only have to add the @IndexedProperty annotation to our property and we get the extra getter and setter methods we want:

import groovy.transform.IndexedProperty

class Group {
    String name
    List members = []
}

class IndexedGroup {
    String name
    @IndexedProperty List members = []
}

def group = new Group(name: 'Groovy')
group.members[0] = 'mrhaki'
group.members[1] = 'Hubert'
assert 2 == group.members.size()
assert ['mrhaki', 'Hubert'] == group.members

try {
    group.setMembers(0, 'hubert') // Not index property
} catch (MissingMethodException e) {
    assert e
}

def indexedGroup = new IndexedGroup(name: 'Grails')
indexedGroup.members[0] = 'mrhaki'
indexedGroup.setMembers 1, 'Hubert'
assert 2 == indexedGroup.members.size()
assert 'mrhaki' == indexedGroup.getMembers(0)
assert 'Hubert' == indexedGroup.members[1]

Wednesday, July 14, 2010

Groovy Goodness: Map with Default Values

In Groovy we can create a map and use the withDefault() method with a closure to define default values for keys that are not yet in the map. The value for the key is then added to the map, so next time we can get the value from the map.

def m = [start: 'one'].withDefault { key -> 
    key.isNumber() ? 42 : 'Groovy rocks!'
}

assert 'one' == m.start
assert 42 == m['1']
assert 'Groovy rocks!' == m['I say']
assert 3 == m.size()

// We can still assign our own values to keys of course:
m['mrhaki'] = 'Hubert Klein Ikkink'
assert 'Hubert Klein Ikkink' == m.mrhaki
assert 4 == m.size()

Groovy Goodness: Get to Know More About a GString

One of Groovy's great features is the GString. With the GString we can write strings containing expressions that are evaluated. We create a GString if our string is inside double quotes. We can found out information about the expressions in our GString with some simple methods and properties:


def user = 'mrhaki'
def language = 'Groovy'

def s = "Hello ${user}, welcome to ${language}."

assert 2 == s.valueCount
assert ['mrhaki', 'Groovy'] == s.values
assert 'mrhaki' == s.getValue(0)
assert 'Groovy' == s.getValue(1)
assert 32 == s.length()
assert 'Hello ' == s.strings[0]
assert ', welcome to ' == s.strings[1]
assert '.' == s.strings[2]
assert 'Hello mrhaki, welcome to Groovy.' == s

Sunday, July 11, 2010

Book Review: Groovy for Domain-Specific Languages

Title: Groovy for Domain-Specific Languages
Paperback : 312 pages (235mm x 191mm)
ISBN : 184719690X
ISBN 13 : 978-1-847196-90-3
Author(s) : Fergal Dearle
Publisher: Packt Publishing
Website
Sample chapter: Building a builder (chapter 7)

Groovy for Domain-Specific Languages has the subtitle 'Extend and enhance your Java applications with Domain-Specific Language in Groovy'. The book is aimed at Java developers who want to write a Domain-Specific Language (DSL) and integrate it with their applications.

Because the book targets a Java audience the first chapters are mostly an introduction to Groovy. The first chapter is an introduction to Groovy and Domain-Specific Languages (DSLs). The author explains some common concepts for DSLs and common examples of DSLs. In the second chapter we learn how to install Groovy and how to write and run scripts. Next we get a brief introduction into the Groovy language features, so as a Java developer we get enough knowledge to get started with Groovy. Features like metaprogramming are covered in a later chapter.

In chapter three the author covers closures. Because Groovy supports closures and they are important for writing DSLs a complete chapter is devoted to closures. This is a good thing, because as Java developers we get a good understanding of the power of closures, we don't have in Java. We learn how to write closures, pass parameters, curry parameters and invoke them. The book doesn't cover the latests Groovy 1.7.2 curry methods, but it is enough to get started.

After the first three chapters we learned enough to write our first DSL. The author explains how we can write our own DSL for a Twitter client. First we learn about the Twitter API and how to use it with the Twitter4J library. Next we are going to make the API calls more Groovy by using closures and Groovy's collection support. This results already in more readable code that doesn't read like normal Java code. We even learn how we can write a command-line script to use the Twitter DSL. The author explains that we can extend from the Script class to provide a very clean DSL that just read like English.

So after the fourth chapter we already can write our own DSL in Groovy with jsut the basic Groovy features. In chapter five the author introduces more powerful Groovy features. We learn about named parameters, builders and the builder design pattern, metaprogramming with Groovy's Meta-Object Protocol (MOP) and the ExpandoMetaClass to enhance classes.

In chapter six the author shows some existing DSLs from the Groovy eco-system. This is a bit theoretical but we get to see Grails' GORM, Gant, and test frameworks like Spock and EasyB. For a Java developer this might be new and shows at least the power of Groovy and what type of DSLs can be achieved.

Builders are a powerful way to work with hierarchical data and constructs. So chapter seven is completely dedicated to builders. This chapter is also available as free chapter for download. The author first explains how we can use closures and the invokeMethod and methodMissing methods to construct a builder. Next we learn how to use the BuilderSupport classes to create our own builders.

In chapter eight we learn how to write our own rules DSL and that is where it really gets interesting. We learn how we can use the bindings support in Groovy for a business rules DSL. We create a DSL to define rewards and promotion rules for an imaginery online media provider. Step by step we build the DSL and write supporting classes to load the DSL rules and execute them with concrete domain object classes.

In the last chapter we learn different ways to integrate the rules DSL from the previous chapter in a Java application. First we see how Groovy and Java integrate. And next we learn how we can integrate the DSL script with GroovyClassLoader, GroovyShell and GroovyScriptEngine.

Groovy for Domain-Specific Languages is a good book to learn how to write a DSL in Groovy. As a Java developer we get enough introduction to Groovy to get started, but if we already know Groovy we can skip the chapters about Groovy's features. It is good that in chapter four we already learned enough to write a DSL for the Twitter API. This shows that writing a DSL doesn't have to be difficult. The rest of the book introduces some more powerful features so in the end we can write a builder and a extensive rules DSL that can be integrated in our Java (or Groovy) applications. The book is a good starting point and provides useful code to get stared with writing our own Domain-Specific Language in Groovy. The author doesn't cover AST transformations as a another way to write DSLs, but with the provided information we can already achieve a lot.

Monday, July 5, 2010

Spocklight: Assert Magic

One of the many great features of Spock is the way assertion failures are shown. The power assert from Groovy is based on Spock's assertion feature, but Spock takes it to a next level. Let's create a simple specification for a course service, which is able to create new courses:

// File: CourseServiceSpec.groovy
package com.mrhaki.blog

@Grab('org.spockframework:spock-core:0.4-groovy-1.7')
import spock.lang.Specification

class CourseServiceSpec extends Specification {

    def "Create new course with teacher and description"() {
        setup:
        def courseService = new CourseService()

        when:
        def course = courseService.create('mrhaki', 'Groovy Goodness')

        then:
        'Mrhaki' == course.teacher.name
        'Groovy Goodness' == course.description
        !course.students
    }

}

class CourseService {
    Course create(String teacherName, String description) {
        new Course(teacher: new Person(name: teacherName), description: description)
    }
}

class Course {
    Person teacher
    String description
    List<Person> students
}

class Person {
    String name
}

At lines 16, 17, 18 we define the assertions for our specification. First of all we notice we don't add the keyword assert for each assertion. Because we are in the then block we can omit the assert keyword. Notice at line 18 we can test for null values by using the Groovy truth. We also notice we only have to write a simple assertion. Spock doesn't need a bunch of assertEquals() methods like JUnit to test the result.

Now it is time to run our specification as JUnit test and see the result:

$ groovy CourseServiceSpec.groovy
JUnit 4 Runner, Tests: 1, Failures: 1, Time: 232
Test Failure: Create new course with teacher and description(com.mrhaki.blog.CourseServiceSpec)
Condition not satisfied:

'Mrhaki' == course.teacher.name
         |  |      |       |
         |  |      |       mrhaki
         |  |      com.mrhaki.blog.Person@34b6a6d6
         |  com.mrhaki.blog.Course@438346a3
         false
         1 difference (83% similarity)
         (M)rhaki
         (m)rhaki

    at com.mrhaki.blog.CourseServiceSpec.Create new course with teacher and description(CourseServiceSpec.groovy:16)

Wow that is a very useful message for what is going wrong! We can see our condition 'Mrhaki' == course.teacher.name is not satisfied, but we even get to see which part of the String value is not correct. In this case the first character should be lowercase instead of uppercase, but the message clearly shows the rest of the String value is correct. As a matter of fact we even know 83% of the String values is similar.

Another nice feature of Spock is that only the line which is important is shown in the abbreviated stacktrace. So we don't have to scroll through a big stacktrace with framework classes to find out where in our class the exception occurs. We immediately see that at line 16 in our specification the condition is not satisfied.

In our sample we have three assertions to be checked in the then. If we get a lot of assertions in the then block we can refactor our specification and put the assertions in a new method. This method must have void return type and we must add the assert keyword again. After these changes the assertions work just like when we put them in the then block:

package com.mrhaki.blog

@Grab('org.spockframework:spock-core:0.4-groovy-1.7')
import spock.lang.Specification

class CourseServiceSpec extends Specification {

    def "Create new course with teacher and description"() {
        setup:
        def courseService = new CourseService()

        when:
        def course = courseService.create('mrhaki', 'Groovy Goodness')

        then:
        assertCourse course
    }

    private void assertCourse(course) {
        assert 'mrhaki' == course.teacher.name
        assert 'Grails Goodness' == course.description
        assert !course.students
    }

}

class CourseService {
    Course create(String teacherName, String description) {
        new Course(teacher: new Person(name: teacherName), description: description)
    }
}

class Course {
    Person teacher
    String description
    List students
}

class Person {
    String name
}

When can run our specification and get the following output:

$ groovy CourseServiceSpec.groovy
JUnit 4 Runner, Tests: 1, Failures: 1, Time: 228
Test Failure: Create new course with teacher and description(com.mrhaki.blog.CourseServiceSpec)
Condition not satisfied:

'Grails Goodness' == course.description
                  |  |      |
                  |  |      Groovy Goodness
                  |  com.mrhaki.blog.Course@3435ec9
                  false
                  4 differences (73% similarity)
                  Gr(ails) Goodness
                  Gr(oovy) Goodness

    at com.mrhaki.blog.CourseServiceSpec.assertCourse(CourseServiceSpec.groovy:21)
    at com.mrhaki.blog.CourseServiceSpec.Create new course with teacher and description(CourseServiceSpec.groovy:16)

Spock provides very useful assertion messages when the condition is not satisfied. We see immediately what wasn't correct, because of the message and the fact the stacktrace only shows the line where the code is wrong.

Thursday, July 1, 2010

Groovy Goodness: Clear Time Portion of a Date

Working with dates in Groovy is easy. We get a lot of extra functionality compared to the standard Java Date class. One of the extra methods added to the Date class since Groovy 1.6.8 is clearTime(). With clearTime() we reset the time portion of a date to 12 o'clock midnight. This makes it easier to compare dates if we only are interested in the date, month, year parts.

// Create new date.
def d = new Date(year: 2010, month: Calendar.JULY, date: 1, 
                                hours: 7, minutes: 12, seconds: 0)

assert '7/1/10 7:12:00 AM' == d.dateTimeString

// Reset time portion of the date.
d.clearTime()

assert '7/1/10 12:00:00 AM' == d.dateTimeString