Recently about Groovy
A recent project started out life as an all-Java project that used Maven as the build tool. Initially we used Atlassian Clover to measure unit test coverage. Clover is a great product for Java code, but unfortunately it only works with Java code because it works at the Java source level. (This was the case as of Spring 2009, and I haven't checked since then.) As we started migrating existing code from Java to Groovy and writing new code in Groovy, we started to lose data about unit test coverage because Clover does not understand Groovy code. To remedy this problem we switched from Clover to Cobertura, which instruments at the bytecode level and thus works with Groovy code. Theoretically it would also work with any JVM-based language but I'm not sure whether or not it could handle something like Clojure or not.
In any case, we only cared about Groovy so Cobertura was a good choice. With the Cobertura Maven plugin we quickly found a problem, which was that even though the code coverage was running, the reports only showed coverage for Java code, not Groovy. This blog shows you how to display coverage on Groovy code when using Maven and the Cobertura plugin. In other words, I'll show how to get Cobertura reports to link to the real Groovy source code in Maven, so you can navigate Cobertura reports as you normally would.
The core problem is pretty simple, though it took me a while to figure out how to fix it. Seems to be pretty standard in Maven: I know what I want to do, but finding out how to do it is the really hard part. The only thing you need to do is tell Maven about the Groovy source code and where it lives. The way I did this is to use the Codehaus build-helper-maven-plugin which has an add-source goal. The add-source goal does just what you would expect; it adds a specified directory (or directories) as a source directory in your Maven build. Here's how you use it in your Maven pom.xml file:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>src/main/groovy</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
In the above code snippet, we're using the "build-helper-maven-plugin" to add the src/main/groovy directory. That's pretty much it. Run Cobertura as normal, view the reports, and you should now see coverage on Groovy source code as well as Java.
My current project (a web application) has a module that is almost entirely written in Groovy. Note: We are using the latest version 1.6.5 of Groovy.
In one of the methods we had some logic similar to the following:
def myMethodToProcessTheList(def listOfThings) {
if (listOfThings && listOfThings.size < 0) {
//Do my logic}
}When the above code is run using Java 5 everything works wonderfully. However when we pushed the code out to our server running Java 6 we got an interesting error stating that it couldn't compare java.util.ArrayList to java.lang.Integer.
The problem is actually that the size method needs the parens after it (Note: The Groovy docs actually do state that methods with at least ONE param can omit the parens). I realize now that it would make sense that parameter-less methods would need parens because how else would Groovy distinguish between methods and property accessors? I did find one forum post that indicated that in Groovy, lists have special properties that act like the spread-dot operator. That is why the listOfThings.size returned the ArrayList instead of a number.
So why does this work in Java 5 but not Java 6? That is a great question, one of which I really don't have a definitive answer. I'm not completely sure if this purely a Java 5/Java 6 difference or simply a difference between the IBM Java 5/Java 6 JVM.
If anyone has a theory as to why it would work one way on Java 5 and the other in Java 6, I would love to hear it.
Example the first: Generics at the end of a line:
def list = [1,2,3] as List<Integer>
println list
If you try to compile this in Groovy it will give you the error message: 'unexpected token: println', however this:
Gives the expected output.def list = [1,2,3] as List<Integer>;
println list
Example the second: Ambiguous Closures
{-> assert GroovyClosureTest == owner.getClass() }()
{-> assert GroovyClosureTest == delegate.getClass() }()
I don't think you'd really ever need to do something like this, but a closure can be defined and called on a single line. Because of Groovy's special closure parameter syntax (e.g. list.each() {} being synonomous with list.each({})) the compiler thinks I'm passing the second closure into the first as an argument. Again a semicolon is needed to seperate the two lines:
{-> assert GroovyClosureTest == owner.getClass() }();
{-> assert GroovyClosureTest == delegate.getClass() }()
Last week I tweeted about groovification, which is defined thusly:
groovification. noun. the process of converting java source code into groovy source code (usually done to make development more fun)
On my main day-to-day project, we've been writing unit tests in Groovy for quite a while now, and recently we decided to start implementing new code in Groovy rather than Java. The reason for doing this is to gain more flexibility in development, to make testing easier (i.e. in terms of the ability to mock dependencies in a trivial fashion), to eliminate a lot of Java boilerplate code and thus write less code, and of course to make developing more fun. It's not that I hate Java so much as I feel Java simply isn't innovating anymore and hasn't for a while, and isn't adding features that I simply don't want to live without anymore such as closures and the ability to do metaprogramming when I need to. In addition, it isn't removing features that I don't want, such as checked exceptions. If I know, for a fact, that I can handle an exception, I'll handle it appropriately. Otherwise, when there's nothing I can do anyway, I want to let the damn thing propagate up and just show a generic error message to the user, log the error, and send the admin team an email with the problem details.
This being, for better or worse, a Maven project, we've had some interesting issues with mixed compilation of Java and Groovy code. The GMaven plugin is easy to install and works well but currently has some outstanding issues related to Groovy stub generation, specifically it cannot handle generics or enums properly right now. (Maybe someone will be less lazy than me and help them fix it instead of complaining about it.) Since many of our classes use generics, e.g. in service classes that return domain objects, we currently are not generating stubs. We'll convert existing classes and any other necessary dependencies to Groovy as we make updates to Java classes, and we are implementing new code in Groovy. Especially in the web controller code, this becomes trivial since the controllers generally depend on other Java and/or Groovy code, but no other classes depend on the controllers. So starting in the web tier seems to be a good choice. Groovy combined with implementing controllers using the Spring @MVC annotation-based controller configuration style (i.e. no XML configuration), is making the controllers really thin, lightweight, and easy to read, implement, and test.
I estimate it will take a while to fully convert all the existing Java code to Groovy code. The point here is that we are doing it piecemeal rather than trying to do it all at once. Also, whenever we convert a Java file to a Groovy one, there are a few basics to make the classes Groovier without going totally overboard and spending loads of time. First, once you've used IntelliJ's move refactoring to move the .java file to the Groovy source tree (since we have src/main/java and src/main/groovy) you can then use IntelliJ's handy-dandy "Rename to Groovy" refactoring. In IntelliJ 8.1 you need to use the "Search - Find Action" menu option or keystroke and type "Rename to..." and select "Rename to Groovy" since they goofed in version 8 and that option was left off a menu somehow. Once that's done you can do a few simple things to make the class a bit more groovy. First, get rid of all the semi-colons. Next, replace getter/setter code with direct property access. Third, replace for loops with "each"-style internal iterators when you don't need the loop index and "eachWithIndex" where you do. You can also get rid of some of the redundant modifiers like "public class" since that is the Groovy default. That's not too much at once, doesn't take long, and makes your code Groovier. Over time you can do more groovification if you like.
The most common gotchas I've found have to do with code that uses anonymous or inner classes since Groovy doesn't support those Java language features. In that case you can either make a non-public named class (and it's OK to put it in the same Groovy file unlike Java as long as it's not public) or you can refactor the code some other way (using your creativity and expertise since we are not monkeys, right?). This can sometimes be a pain, especially if you are using a lot of them. So it goes. (And yes, that is a Slaughterhouse Five reference.)
Happy groovification!
The safe navigation operator is almost certainly my favorite operator in Groovy. It allows you to guard against NullPointerException(s) much more cleanly than defining a nasty if/else mess. Consider the following example.
class Book {
String title
Author author
}
class Author {
String firstName
String lastName
}
def author = new Author(firstName:'Jason')
def book = new Book(title:'Say no to NPEs', author:author)
println book.author?.lastName
Did you see that ?. operator on the last line of the code sample? That's the safe navigation operator, and it's the equivalent of writing the following if statement (although it's much more readable).
if (book.author != null) {
println book.author.lastName
}
The safe navigation operator essentially checks to see if the object you're about to invoke a method on is null. If it is null, it simply skips the method invocation and returns null. If it isn't null, it proceeds as usual. It works for method chaining too, so if you're worried about book being null, you could write
println book?.author?.lastName
This way, if either book or author are null, you simply print out null instead of causing a NullPointerException.
Since learning about the safe navigation operator, I've used it successfully in dozens of classes without any problem. Until last week. Consider the following line of code .
println book?.author?.firstName?.trim().concat(" is great.")
Thanks to the safe navigation operator we can write this concatenation of firstName and a sentence fragment without worrying about NullPointerException(s) and ugly if blocks. Or so I thought.
Looking at this line of code, I thought for sure I was safe from any sneaky NullPointerException. If book, author or firstName are null I'll simply end up printing null and not have to worry about the concat() method. After all, if the trim() method succeeds, there's no sense in guarding it's result for null. And that's where I was wrong.
I naively assumed the method chain would stop once the safe navigation operator encountered a null when in fact it does not. While the trim() method is safe from being called on a null firstName object, it will return null, upon which the concat() method is called. Oops!

