Jim Driscoll's Blog

Notes on Technology and the Web

Archive for September 2012

Property Dispatch on Groovy Objects

leave a comment »

In my last post, I covered Method Dispatch on Groovy Objects.  The next topic is similar, Property Dispatch.

In Groovy, you can specify properties on objects in the same way that you can specify fields in Java:  With the “.” operator.  I.e., if I have an object named “Test”, and it has a class variable named “test”, you can access it with the phrase “Test.test” (just like Java).

As I already mentioned in my Introduction to Groovy, Groovy provides automatic creation of accessors and mutators (get and set).    That’s actually an oversimplification, but we’ll leave it at that for now.  As a result, consider the following Groovy class:

class GetSet {
   def firstField = 1
}

This can be used in the following way, inside a Java class:

GetSet gs = new GetSet();
System.out.println(gs.getFirstField());
gs.setFirstField("test");
System.out.println(gs.getFirstField());

That’s because, under the covers, void setFirstField(Object) and Object getFirstField() are added to the Groovy class.  Note that because the class field is declared as def, the type of these messages is Object.

While that’s handy in Java, in Groovy, we can do so much more with properties.  You can access them with dot notation:

def gs = new GetSet()
gs.firstField = 2.5
println gs.firstField

You can access them with get/setProperty (which is part of GroovyObject, the base object for all objects in Groovy):

def gs = new GetSet()
gs.setProperty('firstField','test2')
println gs.getProperty('firstField')

And you can even access a Map of all the properties on the object, and operate on that:

def gs = new GetSet()
println gs.properties.firstField

This last example is interesting since it’s using a few features of Groovy: the properties property is actually a shortcut to the getProperties() method, which returns a Map.  In turn, you can access the values of the map by using the key in dot notation.  So this is actually a shortcut for the following Java code: 

GetSet gs = new GetSet();
System.out.println(gs.getProperties().get("firstField"));

While all that’s handy, that’s still not dispatch.  In order to handle properties dispatch, there are two different methods we can use.  Consider the following code:

GetSet gs = new GetSet();
gs.newprop = 'new value'
println gs.newprop

newprop doesn’t exist in GetSet – we want to handle adding it at runtime.  The first method to do so is to override missingProperty(String) and missingProperty(String, Object).  The first method handles gets of properties that don’t exist, the second handles sets.  So the following code handles unknown properties seamlessly:

Map props = [:]
    
def propertyMissing(String name, value) {
    props[name] = value
}
    
def propertyMissing(String name) {
    return props[name]
}

In Groovy, Maps can be initialized to be empty with [:] and the values in that map can be accessed with the syntax pattern map[key].  So, in this code, if the property doesn’t exist, it will be added into an internal Map if you are setting it, and that value will be returned when the property is later used.  If the property is accessed before it’s set, a null is returned.  Of course, we could check for existence, and throw an exception if we desired to. 

This method will only add to the existing properties, however.  If there’s already a property (a class instance field, for instance) on the class, such as firstField in our example, this code is never touched.

If instead you want to completely override the access to fields, you can instead override getProperty(String)setProperty(String, Object) and getProperties() for good measure, if desired.  Here’s an example:

Map props = [:]
    
void setProperty(String name, value) {
    props[name] = value
}
    
Object getProperty(String name) {
    return props[name]
}
    
Map getProperties() {
    return props
}

This code actually does almost the same thing as the previous example, except that now, any instance or class fields are hidden from property access.    Meaning that the following code prints null:

GetSet gs = new GetSet();
println gs.firstField

But note that the following code will still print 1:

GetSet gs = new GetSet();
println gs.@firstField

This is because we’re using the “Java field accessor” in the second example – the .@  notation bypasses get/setProperty methods, and directly act on the underlying Java field.

Dispatch is just a short step away from the above code.  Instead of using the internal Map of properties, you could instead route the property lookup anywhere – an xml file, a database, or any other class or computation.

So, now that we’ve looked at method and property dispatch, we’ll run through some ways to use these in a DSL next time.  Until then…

 

Advertisements

Written by jamesgdriscoll

September 29, 2012 at 12:19 PM

Posted in DSL, Groovy

Method dispatch on Groovy objects

leave a comment »

 

As I promised my post about optional parenthesis, today I’m going to talk about method dispatch in  Groovy – specifically, dynamically dispatching methods on Groovy objects via the invokeMethod mechanism.  We’ll tie it into DSL creation in a later post.

The key method to know about for method dispatch is GroovyObject.invokeMethod(String name, Object args).  This method is located on GroovyObject, and is called when the method you called isn’t present on the object.

Consider the following Groovy code:

class Test {
  def invokeMethod(String name, args) {
    println "called invokeMethod $name $args"
  }

  def test() {
    println 'in test'
  }
}

def t = new Test()
t.test()
t.bogus('testing!',1,2,3)

 

This code prints out the following text, when run in groovyConsole:

in test
called invokeMethod bogus [testing!, 1, 2, 3]

the first call goes to the test method, as usual.  The second call, instead of resulting in a MissingMethodException, will route through the invokeMethod method.

This can be handy for all kinds of things, but the use I’ve put it to is as a dispatcher, routing calls to an underlying class or set of classes – here’s an example:

 

class One {
  static def test1() {
    println 'in test1'
  }
}

class Test {
  def invokeMethod(String name, args) {
    if (One.metaClass.respondsTo(One, name, *args)) {
      return One."$name"(*args)
    }
  }
}

def t = new Test()
t.test1()

This prints out 

in test1

Now, this example is flagrantly using a few tricks in Groovy, so let me mention how they work…  (Feel free to skip this paragraph if you’re content with this being a magic incantation.)   The first bolded line, with the respondsTo method, will retrieve the metaClass of the One class, which acts in a similar way to the Class class, but allows additional capabilities.  The respondsTo method of MetaClass takes, as it’s first argument, the actual object (or class, for static methods) that you’re checking, the name of the method, and then the arguments.  The asterisk in front of the “*args” argument is called the “spread operator”, and will derefrerence the array of args to instead be a list of arguments placed at the end of the method call.  The second bolded line is using the String substitution capability of Groovy’s double quoted Strings (called GStrings) to dynamically execute the method called name, again passed the arguments with the spread operator.  An additional wrinkle is that respondsTo actually  returns a ArrayList – which is treated as false by Groovy if empty, and true if not.  Now, you could do all this in Java, via reflection and other code, but the pain of doing so really makes this something you should probably do in Groovy.

There’s one other case we should probably cover – if your class implements the marker interface GroovyInterceptable, it won’t just intercept methods it can’t find – it will intercept all method calls on the class, including methods that are actually there.  That unfortunately means that we can’t directly call the method from within the invokeMethod though – instead, you must use the metaClass to invoke the method, getting around that interception.  Here’s how:

class One {
  static def test() {
    println 'in One.test'
  }
}

class Test implements GroovyInterceptable {
  def firstTime = true
  def invokeMethod(String name, args) {
    if (firstTime) {
      firstTime = false
      return One."$name"(*args)
    }
    return metaClass.getMetaMethod(name,args).invoke(this,args)
  }
  def test() {
    println 'in Test.test'
  }
}

def t = new Test()
t.test()
t.test()

 

This prints out:

in One.test
in Test.test

 

We’ll leave the explanation of how all this works for another time – the MetaClass is used pretty heavily in all kinds of Metaprogramming in Groovy, and we’ll cover it pretty extensively as we go on – but it’s use should be obvious from context.  Note that unlike our other use of args, we do not need to use the spread operator.  But keep the MetaClass in mind, because when it comes to adding methods dynamically at runtime, it’s the way to go.

Next up, we’ll talk about the related topic of Property Dispatch.

Written by jamesgdriscoll

September 29, 2012 at 10:30 AM

Posted in DSL, Groovy

Word order and Groovy Parsing

leave a comment »

 

In my previous post on Optional Parenthesis in Groovy, I mentioned using the optional parenthesis to make natural looking chains of commands.  But I realize that I overlooked mentioning a really important limitation with this approach, namely, how Groovy will parse these parentheses lacking statements.

Consider this code:

one two three four five

Since Groovy is a dynamic language, this statement will need to figured out by Groovy at compile time with almost no available context.  Is the token one a method, or a binding variable?  That information isn’t available to the compiler, so Groovy has to guess.  Here’s how to figure out what Groovy will do:

Fire up groovyConsole from a command line which has the GDK in it’s PATH.

Type in the line above.

From the menus, select Script -> Inspect AST

In the lower pane of the frame that pops up, you’ll see what Java code is going to be generated by the Groovy parser.  Take special note of the run() method – that’s the part that actually contains the code we typed in, turned into the code below:

public java.lang.Object run() {    
    return this.one(two).three(four).five
}

This really tells us all we need to know about how Groovy’s going to parse a String of words – it’s going to always follow the pattern:

method(param).method(param).variable

Where the first two words are going to be treated as a method name and a parameter (from a binding variable or locally scoped variable), respectively, while any odd instance will be a variable.

So, while you can use optional parentheses to construct a grammar, you should be aware that there are significant restrictions on how you can do so.

Written by jamesgdriscoll

September 15, 2012 at 11:52 AM

Posted in DSL, Groovy