Of course, no introduction of myself would be complete without introducing my wife (CLICK!) And my four children (CLICK!)
Consider the following Groovy class….it’s a Duck, and as any good Duck should, it walks like a duck and quacks like a duck. (CLICK!) Now, consider this Groovy class….it’s a MentalPatient, and it just so happens to walk like a duck and quack like a duck. (CLICK!) Now, consider the Groovy class….it claims to walk with ducks. It defines one method, with an interesting type declaration in its signature (CLICK!) Here we have a dynamic type declaration….”def”….this allows us to pass in either a Duck or a MentalPatient…and to WalksWithDucks, as long as it walks like a duck…. (CLICK!) It’s a duck!!!
At the end of the day, it’s all in what you respond to! (CLICK!) Here we see one of Groovy’s metaprogramming constructs, the “respondsTo” method, which allows us to see whether or not a given object responds to certain method calls, irrespective of any class or interface implementation
In Groovy application, 3 kinds of objects: POJO’s (Plain Old Java Objects) -> regular Java objects created in Java or other JVM languages (JRuby, Jython, etc.) POGO’s (Plain Old Groovy Objects) -> written in Groovy, extend java.lang.Object, implement groovy.lang.GroovyObject Groovy interceptors -> written in Groovy and implement GroovyInterceptable invokeMethod(), getProperty(), setProperty() – make Groovy objects highly dynamic – can be used to work w/ methods and properties created on the fly getMetaClass()/setMetaClass() – make it very easy to create proxies to intercept and also inject methods on a POGO
Marker interface that extends GroovyObject All method calls – both existing and nonexisting methods – on an object implementing this interface are intercepted by its invokeMethod()
Groovy allows metaprogramming for POJO’s and POGO’s POJOS – Groovy maintains a MetaClassRegistry class of MetaClasses POGOS – direct reference to their MetaClass When you call a method: Groovy first checks whether the target is a POJO or POGO, and handles such calls differently If it is a POJO, Groovy fetches its MetaClass from the MetaClassRegistry and delegates method invocation to it. Any interceptors or methods you’ve defined on its MetaClass take precedence over the original method of the POJO For POGO’s, Groovy takes a few extra steps (CLICK!)
If the class implements GroovyInterceptable, all calls get routed to its invokeMethod() If not, then Groovy looks for the method first in the POGO’s MetaClass, and then if not found, in the POGO itself, executing in that order of preference If the POGO does not have either, it then looks for a property with that method name. If found, and if its type is Closure, it invokes the Closure. If no closure property, it invokes methodMissing() if it exists If not, it invokes the POGO’s invokeMethod() If all else fails, Groovy throws a MissingMethodException indicating the failure of the call
Suppose we have a Car class for which we want to call its check() method to perform filtering prior to any other method call CLICK! Here we implement invokeMethod()….CLICK! First, we check to see if the name of the method is not check()….if not, we get access to the check() MetaMethod and invoke it….CLICK! Next, we try to access the MetaMethod for the method that was called…CLICK! If we don’t get a null, we know we have a valid method, and we invoke it…CLICK! Otherwise, we delegate the call to the Car MetaClass’s invokeMethod()….the default implementation throwing a MissingMethodException….CLICK! Here’s some client code…we call the 3 valid methods and then one invalid method…CLICK! And here’s the output….notice that for start() and drive() we run the filter….but when check() is called directly, we do not….and again, notice the MissingMethodException on speed()
We can do the same thing using MetaClass…there are a few subtle differences: (CLICK!) We actually implement invokeMethod on the Car MetaClass by implementing a closure and assigning it to that method name. (CLICK!) Instead of passing “this” to invoke, we pass “delegate.” In a closure, delegate refers to the object that owns the closure. (CLICK!) Lastly, we call invokeMissingMethod() on the metaClass since we are already executing invokeMethod() and would not want to call that method recursively. invokeMissingMethod() actually delegates to invokeMethod() in the case of existing methods, and to missingMethod() in the case of nonexisting methods
We can also use MetaClass on a POJO…in this case the java.lang.Integer class (CLICK!) Again, we’re implementing a closure and assigning it to invokeMethod on the Integer class (CLICK!) The closure simply checks for a valid method call, invokes pre-filtering code, invokes the method, and invokes post-filtering code. Here is some client code….the first two calls exist on Integer, while the third does not… (CLICK!) And here is the output…..notice the execution of the filters for the valid method calls and then the MissingMethodException thrown on the call to empty()
So here we’re going to implement a StringUtil class containing a single method, toSSN(), that we’d like to be vailable on both String and StringBuffer…it will format the contents of the string as a social security number. So to do category injection, there are a few requirements: (CLICK!) First, you need a static method…(CLICK!) That accepts at least one parameter (the object for which the method is to be injected) (CLICK!) You write a use block, with the Category class as the argument…in this case, any Object inside the use block will have access to the toSSN() method because we left toSSN() dynamically typed (CLICK!) Objects outside the scope of the use block will not have toSSN()….(CLICK!) And here is the output…
I want to show you a second example of this to futher illustrate the flexibility….here we have a FindUtil class with an extractOnly() method….(CLICK!) Again, the method is static….(CLICK!) It takes the object (in this case a String) on which to inject the method as the first parameter….(CLICK!) And it also takes a second argument, in this case a closure that we expect to return a boolean value…(CLICK!) Inside the method, we iterate over each character in the String and append to the result only characters for which the closure returns true. You’ll see “it” here, which happens to be the default argument in closures if none are specified…(CLICK!) We setup our use block and execute the code (CLICK!) In this case, we pass in a closre that returns true only if the scanned character is a ‘4’ or a ‘5’….given the String of characters we start with, we get 54 as the output…
Here we’d like to add a method….daysFromNow()….to the Integer class…it will return an instance of java.util.Date equal to the Integer number of days from today….(CLICK!) Now you can tell I only made this slide a couple of days ago …. :-)
We can also add a property in a similar way by implementing the “getter” method for a property called daysFromNow….this allows us to drop the parenthesis, creating a more “fluent” or human readable interface, something you like to shoot for when building domain specific languages…CLICK! Here’s the output….
We can also add a static method by implementing methods on the static property of the metaClass…here’s we’ll add a method indicating whether or not its argument is an even number….CLICK! Again, here’s the output….
The last method type we can add in is a constructor…we do this by appending a closure to the existing set of constructors on Integer….in this case, we want to construct an Integer equal to the current day of the year…CLICK! And the output….
Let’s define a Person class that plays several sports…CLICK! First we’ll implement methodMissing()…CLICK! We’ll search for the suffix of the method named called….in this case we’re expecting method calls like “playFootball” or “playPolo”….CLICK! Having found it, we’ll return a String that says we’re “playing” the sport….here we’re using Groovy’s ability to execute arbitrary Groovy code embedded in a String inside the ${} construct…. CLICK! If we don’t find a legal method name, we throw a MissingMethodException….here’ some client code with several legal calls and one illegal call….CLICK! And here’s the output….notice that methodMissing() is not called for the work() method, but is for all of the sports-related methods….and we got a MissingMethodException for politics, which is usually not a sport, depending on who you’re talking to….
Now let’s implement the Intercept, Cache, Invoke pattern on our Person class…CLICK! First we intercept the method call, just as we did before. Having found it….CLICK! We implement a closure and add it to the Person’s MetaClass…again we’re using Groovy’s String evaluation capabilities to dynamically construct the method name….CLICK! We then return the result of the closure we just implemented….CLICK! Quickly notice the static initializer block….here I’m simply “touching” the metaClass for Person. The reason for this is an eccentricity in Groovy in that ExpandoMetaClass is not the default MetaClass for Groovy, however once you access it the first time it is replaced with an instance of EMC. This may be changed in future versions….CLICK! Here’s some client code…CLICK!….and here’s the output. Notice that methodMissing() is only called once
So here’s the beginning of our DSL….the first thing we do is enable the ExpandoMetaClass globally….this causes methods we add to a parent class, in this case Number, to be available to its children….CLICK! Next we reimplement Number’s get Property method….we assign it a closure that uses Jscience’s API to instantiate an Amount equal to the value of the Number instance and units specified by the propery name…. I’ve added a few examples of this and….CLICK!….here’s the output
The next step is to define our operator overloading….since Jscience doesn’t use the same operation names as Groovy, we need to implement a few closures to massage out the differences…..I’ve put here examples of Multiplication Division Addition Subtraction Powers Opposites And comparisons…and CLICK! Here’s the output…..notice on the power example we mixed metric and english units, and Jscience guessed that we’d want the output in metric units (indicated by the question mark)…
Our third step is to allow us to specify inverse units in a clean way, just like a physicist would. In a Groovy script like this one, all variables are local variables….however you can also pass in variables through a Binding, allowing for easy integration with existing Java code, etc. Here we’re going to implement a binding that will ignore references to the out property, which represents System.out….otherwise, it will return an amount equal to 1 unit of the symbol representing the property we tried to access…. Now, you can see these examples of inverse units, such as kilometers per hour, milligrams per Liter, etc…CLICK! And here’s the output of this portion….
Finally, we’d like to easily do conversions between different units, so we define a to() method on Amount’s metaclass….here’s some examples of that and CLICK! The output