10
Aug
09

some groovy metamagic in practice



When writing scripts, you’re not always interested in having a large number of classes. I know I want to get things done quick.

Java’s standard library already contains most of the stuff you’d need to use. But … it’s too verbose!
This reads a file line by line and prints it to stdout :


import java.io.*;
import java.net.*;

public class xr {
    public static void main(String[] args) {
        try {
            BufferedReader br = new BufferedReader(new FileReader(args[0]));
            while(true) {
                String line = br.readLine();
                if(line == null)
                    break;
                System.out.println(line);
            }
            br.close();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}

This is the Groovy equivalent :


if(args[0]) {
   new File(args[0]).readLines().each {
      println it
   }
}

That was only a fraction of what Groovy is capable of doing.

In a dynamic language, you skip the type declaration, and sometimes bad objects get sent to some functions.
For example, today at work I kept receiving this error :

Caught: groovy.lang.GroovyRuntimeException: Could not find matching constructor for: java.io.File(java.io.File)
	at xr.run(xr.groovy:1)

Some of my methods were expecting a String parameter, which they would convert to a File object. But … they received File objects, and everything blew up. One way of solving this is to make sure you’re only sending Strings, or if the parameter’s a File, you can convert it to a String, and then the method will create a File out of it.

Bad logic, right?

It turns out there’s another alternative to this, a groovier way. What if we add another constructor to the File class? If this were Java, we would have had to open the source file, add the constructor and recompile.
Luckily, Groovy lets us add behavior at runtime.


File.metaClass.constructor << { File param ->
   return new File(param.absolutePath)
}

This solved my problem. Even though it ( probably ) wasn’t the greatest solution to my problem, for me it was a great fix.

Another script I wrote was executing another binary, whose output it captured and processed. The string needed to execute the binary was build at runtime, but somewhere along the way, I kept receiving exceptions. So … I thought about adding some traces. Because I didn’t want to add println statements only so that I could remove them when things started to work, I turned to another metaprogramming solution: method interception.
Basically, this allows you to do something to a method. For example, you could modify the arguments before passing them to the method, or you could add traces ( like in my case ). Here’s the code you I used with the String class:


String.metaClass.invokeMethod = { method,args ->
    def metaMethod = delegate.metaClass.getMetaMethod(method,args)
    println "executing $method with args $args on $delegate"
    return metaMethod.invoke(delegate,args)
}

and that would show you a message when any of String’s methods get called. It can be of great help, trust me πŸ™‚

Another thing you can override is how the properties are being accesed. For example this two snippets of code are equivalent:

first

def a = new File("file.txt")
println a.getAbsolutePath()

second

def a = new File("file.txt")
println a.absolutePath

The difference is, the second version won’t show up when you add tracing to the method calls. If you want those to show up as well, you write code like the following :


File.metaClass.getProperty = { prop ->
	println "called prop $prop"
	def metaProp = delegate.metaClass.getMetaProperty(prop)
	return metaProp.getProperty(delegate)
}

I hope you can put this information to good use … I use these all the time πŸ™‚


7 Responses to “some groovy metamagic in practice”


  1. 1 Lance
    August 11, 2009 at 13:00

    Thanks, these are the practical sorts of metaprogramming I like to see.

  2. 2 RJ
    August 11, 2009 at 13:01

    Nice post. “Metamagic” is right. Keep it up.

  3. August 12, 2009 at 03:40

    Damn, you’ll get me to try out groovy πŸ˜›

    I like how easy it is to add your stuff at method calls, much nicer syntax than checking inspect.isfunction in __getattribute__ IMHO.

  4. 4 geo
    August 12, 2009 at 06:20

    Yeah, Groovy’s pretty cool πŸ™‚

  5. 6 omgo
    October 22, 2009 at 00:18

    Meta programming with groovy is cool. There are some gotchas you would encounter like this one I got recently http://wp.me/poQyb-j


Leave a comment


Blog Stats

  • 281,753 hits