Becoming an Advanced Groovy Developer: Part Two

The following post is based on my presentation at Springone 2GX, entitled “Becoming an Advanced Groovy Developer”.

Mixing Java and Groovy

One of the nice things about Groovy is that it doesn’t ask you to give up your investment in your existing Java libraries. As a matter of fact, you can continue to use Groovy with the popular Java libraries you may already be familiar with such as the Apache Commons projects, or you can even continue to use Groovy with your own proprietary libraries that you may have created to work with your business domain or in your specific infrastructure. However, since Groovy apps are usually distributed as a set of scripts rather than a compiled artifact, we need to find a better way to package up and distribute our dependencies.

This is where Grape comes in.

Grape stands for Groovy Adaptable Packaging Engine or Groovy Advanced Packaging Engine. Grape is a dependency management system built right into Groovy. One of the best things about Grape is that it’s natively supported in the Groovy language, which means it’s already available in your runtime. Grape is built on the popular Ivy dependency management system from the Java space.

Grapes Example

@Grab(group='joda-time', module='joda-time', version='2.8.2')
 import org.joda.time.DateTime
 import org.joda.time.format.DateTimeFormat
 gpx.rte.rtept.each {
      println it.@lat
      println it.@lon
      def printableTime = new DateTime(it.time.toString())
      def format = DateTimeFormat.forPattern('MM/dd/yyyy - hh:mm aa')
      println printableTime.toString(format)
 }

Here is an example of calling the joda time api for a Groovy file.

Let’s take a moment to look at this Grapes annotation block. The first Grapes annotation sets up the various grab annotations for the various dependencies that we can bring in. There is a single grab annotation in this example. The first parameter is the group parameter and generally corresponds to the group that’s responsible for maintaining that dependency. In our case since Joda-Time is a self-managed, open-source project, this simply is called joda-time. The next parameter module specifies the package name that that particular group may be maintaining. Once again, Joda-Time is self-managed so the module name in our case is also joda-time. The last parameter is the version tag specifies the version of the dependency.

@Grapes([
     @Grab(group='commons-primitives', module='commons-primitives', version='1.0'),
     @Grab(group='org.ccil.cowan.tagsoup', module='tagsoup', version='0.9.7')])
class Example {
     // ...
}

In order to do multiple grab annotations you need to add the Grapes annotation as well, you can see that here in this example.

Metaprogramming

When we first learn Groovy we marvel at the convenience methods that are available like list.each and string.execute. Now as we move into advanced developers we no longer just use the existing meta programming we do it ourselves. Metaprogamming is where programs change other programs, this allows us to synthesize methods, intercept calls and make objects act like different types. These all are happening at runtime, of course, we can also do compile time Abstract Syntax Tree (AST) Manipulation as well.

The metaclass is like a class in Groovy, but unlike a regular object in the JVM it is not fixed and can be changed at runtime. Contrary to the regular Java Class object, it does not bear a special meaning and can be changed.

Before invoking a method on an object, Groovy first consults its metaclass. So changing or extending a metaclass makes an impression of object changing its class at runtime. But where the metaclass is stored? To find out, we need to explore various kinds of object first.

We can have following kinds of objects in Groovy:

Plain Old Java Objects (POJOs) – instances of regular java objects created on JVM.

Plain Old Groovy Objects (POGOs) – subclasses of GroovyObject. An interface that adds

getMetaClass(), setMetaClass(MetaClass metaclass)

Groovy Interceptors – subclasses of GroovyInterceptable

Metaprogramming is available for POJOs and POGOs. Groovy interceptors have their own way of achieving similar flexibility. With a POGO it is simple. You need to call its setMetaClass method and a reference to this metaclass is stored within the object. With POJO this is impossible – they are not designed to store a metaclass reference.

For this reason, Groovy maintains an application wide MetaClassRegistry which maps java.lang.Classes to metaclasses.

public class PlainOldJavaClass {
      public void pojoOnly() {System.out.println("From PlainOldJavaClass "); }
      public void pojoOnly() alsoInMetaClass() {
      System.out.println("From PlainOldJavaClass"); }
 }
 PlainOldJavaClass.metaClass.alsoInMetaClass = { println 'From metaClass' }
 PlainOldJavaClass.metaClass. metaClassOnly = { println 'From metaClass }
 PlainOldJavaClass pojo = new PlainOldJavaClass();
pojo. pojoOnly() 
 prints From PlainOldJavaClass
pojo.alsoInMetaClass()
 prints From metaClass
pojo.metaclassOnly()
 prints From metaClass

Method Resolution Order

We know that each POJO and POGO has an associated metaclass (either holds the reference directly or has it stored in an application-wide registry). If you invoke a method on POJO then Groovy first inspects its metaclass. If the method exists in the metaclass it takes precedence over the regular one. We can see that the metaclass methods take precedence. A regular method is even not required.

With POGOs, there are more steps. If you want to invoke a method the steps are as follows. If the method exists in metaclass it is invoked. If the method exists in regular class it is invoked. If there is a field with a method name and this field holds a reference to a closure then the closure is called. If there is a methodMissing() then it is called. If there is invokeMethod() then it is called. Otherwise, the MethodMissingException is thrown.

Groovy Interceptors

Groovy Interceptors are simply POGOs implementing the GroovyInterceptable marker interface. In case of the interceptors all method invocations (both existing and non- existing) are routed to invokedMethod().

class CoolNewGroovyObject {
     void regularMethod() { println "GroovyObject#regularMethod" }
     def closureProperty = { println "GroovyObject#property" }
     Object methodMissing(String name, Object args) { println "Method missing: ${name}" }
     def regularProperty = "This is a nice String"
}
GroovyObject.metaClass.metaMethod = { println 'From metaclass' }
GroovyObject go = new CoolNewGroovyObject()
go.metaMethod() // prints From metaclass
go.regularMethod() // prints GroovyObject#regularMethod

CodeNarc

This summer we had a group of interns writing Groovy and Grails code. I talked a bit about this in my presentation earlier. We setup Codenarc to analyze their code. These type of tools are no pancea but they can help spot problems. I remember years ago using Findbugs to look at some Java web applications. We used it to help our interns analyze code for any bugs before they would check it in.

Codenarc is a static analysis tool for Groovy code that help you find bugs and potential issues.

You can write your own custom rules for CodeNarc to check for items you want to track. There are lot of sample rules you can download and use.

It is easy to setup Code Narc and start using it to look over an existing code base.

This is a sample Codenarc report. As you add custom rules you can pinpoint key areas. You can run codenarc from your IDE manually or you set it up to run from your continuous integration server and send reports. If you have a legacy codebases it may find a lot of changes to make. In that case you might refer to the priority as you can see by this sample report.  Some of the things it will flag can be pretty minor.

CodeNarc has basic rules to constant if and asserts, empty statements, hardcoding, and dead code. It also allows you to check the naming of classes as if a class name is the same as a super class or if it has a confusing method name. Size and complexity can be checked as well with the ABCMetricRule which looks at maxMethodABCScore, maxClassAverageMethodABCScore, and maxClassABCScore. The ABC score is a measure of program size that can be used across many codebases. Codenarc can also check your Groovy code for unused objects, arrays, private fields or variables.

 

No comments yet.

Leave a Reply

Powered by WordPress. Designed by Woo Themes