Creating MS Word reports with Java

If your application stores a lots of user content, it seems to be an obvious idea to offer some template mechanism, which can be used by your customers to create reports. So, the user can get a printable, styled and easy to process version of the interesting information out of your system, designed by himself and filled with data with just one click. Of course, creating and styling those templates should be easy enough for your customer to do it by himself… so, whats about using the well-known MS Word application for it? The user creates a document with his beloved office suite from Redmond, containing formatted text, images and charts and finally adds also some placeholders. Afterwards he passes this document to your application and, whenever the user wants to create a report, you magically fill the placeholders with the actual data from your system. Reporting can be so easy … if you can find some way to manipulate the word document the correct way with the tools your platform offers!

Continue reading

Advertisements

Why findAll on null returns empty lists in Groovy

Recently while debugging our grails application I saw something like this:

variable.findAll { it.condition }

Since the debugger told me that this variable was null, I happily thought I might have found my little bug and moved on waiting for the big crash and a nice NullPointerException. Instead I got an empty list.

Wait WAT?

That seemed rather bizarre to me, so I checked it inside a groovy shell.

null.findAll { true } ==> []
null.findAll { false } ==> []
null.findAll { it } ==> []
null.findAll {} ==> []
null.findAll() ==> []

Ok, what’s going on here? First thing to note is that Groovie’s null is an object.

null.getClass().name ==> org.codehaus.groovy.runtime.NullObject

From the Java perspective kind of surprising but since I’m familiar with Ruby it was somehow expectable. So far no magic, but where does that findAll method come from?

null.getMetaClass().methods*.name
==> [equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait, getMetaClass, getProperty, invokeMethod, setMetaClass, setProperty, asBoolean, asType, clone, equals, getNullObject, getProperty, hashCode, invokeMethod, is, iterator, plus, setProperty, toString]

Not there… so Groovy-Voodoo. Luckily there are some developers more experienced with Groovy than me in our company (even one who contributed to it some time ago), so I could ask someone else than Google. We got the source code (Groovy 1.8 in our case) and dug into it. The place where a lot of those magical methods dwell is DefaultGroovyMethods.java. According to the documentation the static methods in this class will be available in the class of each method’s first parameter. So here we found the following:

public static Collection findAll(Object self, Closure closure) {
    List answer = new ArrayList();
    Iterator iter = InvokerHelper.asIterator(self);
    return findAll(closure, answer, iter);
}

Which at least explains why that is available for null. Furthermore it shows us that findAll should work on any Object, too. A quick check in the console confirms this.

new Object().findAll { true } ==> [java.lang.Object@79ad86e9]

However it does not explain how the invocation works and why the result is []. So what’s happening here? The asIterator method simply invokes a method named iterator on self. Groovie’s NullObject defines this particular method in the following way:

public Iterator iterator() {
    return Collections.EMPTY_LIST.iterator();
}

This clearly explains why we get an empty list from our findAll call. In the case of an arbitrary GroovyObject we again find (after an unsuccessful lookup in GroovyObject.java) the iterator method for objects in the DefaultGroovyMethods class simply putting the object into a collection and iterating over it.

public static Iterator iterator(Object o) {
    return DefaultTypeTransformation.asCollection(o).iterator();
}

What is still missing to a full understanding of this phenomenon is how those default groovy methods get invoked. Covering this would be way beyond the scope of this blog post. If you browse around a little in the source all this meta stuff can get kind of overwhelming. What we can take out of this so far (beside getting confused by Groovie’s method invocation mechanisms) is some more awareness to the fact that anything and everything can happen in languages such as Groovy even when it all starts with an innocent null object…