Recently about Groovy
Near Infinity is proud to host a new Gradle Expert Training class, taught by Tim Berglund, the Author of the Gradle O'Reilly Book Series. This is an intensive and highly practical 3-day Gradle course. You will become familiar with all major concepts of Gradle and how to best use Gradle for simple as well as complex build scenarios. This course is packed with hands-on exercises.
To learn more please visit Gradeware's Gradle Expert Training course description. To register visit Gradeware's Gradle course registration web page.
Be sure to check out our Upcoming NIC-U Training Courses page for information on more upcoming courses.
In 2009 I published a two-part series of articles on IBM developerWorks entitled Groovier Spring. The articles showed how Spring supports implementing beans in Groovy whose behavior can be changed at runtime via the "refreshable beans" feature. This feature essentially detects when a Spring bean backed by a Groovy script has changed, recompiles it, and replaces the old bean with the new one. This feature is pretty powerful in certain scenarios, for example in PDF generation; mail or any kind of template generation; and as a way to implement runtime modifiable business rules. One specific use case I showed was how to implement PDF generation where the Groovy scripts reside in a database, allowing you to change how PDFs are generated by simply updating Groovy scripts in your database.
In order to load Groovy scripts from a database, I showed how to implement custom ScriptFactoryPostProcessor and ScriptSource classes. The CustomScriptFactoryPostProcessor extends the default Spring ScriptFactoryPostProcessor and overrides the convertToScriptSource method to recognize a database-based script, e.g. you could specify a script source of database:com/nearinfinity/demo/GroovyPdfGenerator.groovy. There is also DatabaseScriptSource that implements the ScriptSource interface and which knows how to load Groovy scripts from a database.
In order to put these pieces together, you need to do a bit of configuration. In the articles I used Spring 2.5.x which was current at the time in early 2009. The configuration looked like this:
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!-- set data source props, e.g. driverClassName, url, username, password... -->
</bean>
<bean id="scriptFactoryPostProcessor"
class="com.nearinfinity.spring.scripting.support.CustomScriptFactoryPostProcessor">
<property name="dataSource" ref="dataSource"/>
</bean>
<lang:groovy id="pdfGenerator"
script-source="database:com/nearinfinity/demo/DemoGroovyPdfGenerator.groovy">
<lang:property name="companyName" value="Database Groovy Bookstore"/>
</lang:groovy>
In Spring 2.5.x this works because the <lang:groovy> tag looks for a Spring bean with id "scriptFactoryPostProcessor" and if one exists it uses it, if not it creates it. In the above configuration we created our own "scriptFactoryPostProcessor" bean for <lang:groovy> tags to utilize. So all's well...until you move to Spring 3.x at which point the above configuration no longer works. This was pointed out to me by João from Brazil who tried the sample code in the articles with Spring 3.x, and it did not work. After trying a bunch of things, we eventually determined that in Spring 3.x the <lang:groovy> tag looks for a ScriptFactoryPostProcessor bean whose id is "org.springframework.scripting.config.scriptFactoryPostProcessor" not just "scriptFactoryPostProcessor." So once you figure this out, it is easy to change the above configuration to:
<bean id="org.springframework.scripting.config.scriptFactoryPostProcessor"
class="com.nearinfinity.spring.scripting.support.CustomScriptFactoryPostProcessor">
<property name="dataSource" ref="dataSource"/>
</bean>
<lang:groovy id="pdfGenerator"
script-source="database:com/nearinfinity/demo/DemoGroovyPdfGenerator.groovy">
<lang:property name="companyName" value="Database Groovy Bookstore"/>
</lang:groovy>
Then, everything works as expected and the Groovy scripts can reside in your database and be automatically reloaded when you change them. So if you download the article sample code as-is, it will work since the bundled Spring version is 2.5.4, but if you update to Spring 3.x then you'll need to modify the configuration in applicationContext.xml for example #7 (EX #7) as shown above to change the "scriptFactoryPostProcessor" bean to be "org.springframework.scripting.config.scriptFactoryPostProcessor." Note there is a scheduled JIRA issue SPR-5106 that will make the ScriptFactoryPostProcessor mechanism pluggable, so that you won't need to extend the default ScriptFactoryPostProcessor and replace the default bean, etc. But until then, this hack continues to work pretty well.
On my current project we have been involved in converting some of the hundreds of manual tests that are run by our Test Team every release into a suite of automated Selenium RC tests.
During the course of this adventure my crew found several instances where XPath and native JavaScript were not sufficiently expressive to find elements in some of our more complicated interfaces.
Since our web app uses the Prototype/Scriptaculous JavaScript framework we wanted to find a way to make the locating power of Prototype available within Selenium RC.
We developed approaches for both Selenium 0.9.2 and Selenium 1.0.3 (which had better programmatic support for adding JavaScript user extensions to Selenium).
Selenium 0.9.2
Selenium RC provides the capability to add "user extensions" to augment its JavaScript core.
See http://seleniumhq.org/docs/08_user_extensions.html for detailed information on how to set this up.
We wrote the following user-extension.js file:
Selenium.prototype.setupProtoypeJS = function() {
id = selenium.browserbot.getCurrentWindow().$;
css = selenium.browserbot.getCurrentWindow().$$;
}In our code we have a base class for all our test cases. To this we added our own waitForPage() method:
public void waitForPage() {
selenium.waitForPage('60000')
proc.doCommand('setupPrototypeJS', [])
}Thus every time the page reloads (which clears the JavaScript context) we call waitForPage() and this command is re-executed. It creates two global variables (id and css) and binds them to Prototype's $ and $$ functions respectively.
Note: The reason we choose id and css instead of $ and $$ was that Groovy considers $ in Strings to be a special character and we would have had to escape it each time it was used.
The Prototype selectors can now be used in Selenium RC like this:
selenium.click("dom=id('foo')")
selenium.click("dom=css('.bar')")
selenium.click("dom=css('span.foo a.baz')")Note: You still have to specify the dom locator type so Selenium RC will know to execute your locator string as JavaScript.
Selenium 1.0.3
In more recent version of Selenium RC the project added the setExtensionJs() method. This allows you to set extension JavaScript programmatically prior to starting the selenium client:
selenium = new DefaultSelenium(...)
selenium.setExtensionJs('...')
selenium.start()
This made it much easier to implement our Prototype bindings. The only trick was that the JavaScript seems to be executed prior to having access to a page context and is also only executed once. This required us to take a different approach.
We created id and css as global functions instead of variables. This allowed us to defer accessing the current window until the functions were actually invoked.
selenium.setExtensionJs('''
id = function(value) {
return selenium.browserbot.getCurrentWindow().$(value);
}
css = function(value) {
return selenium.browserbot.getCurrentWindow().$$(value);
}
'''); Note: The above code snippet is written in Groovy which allows multiline Strings.
The Prototype selectors are used in Selenium RC like before:
selenium.click("dom=id('foo')")
selenium.click("dom=css('.bar')")
selenium.click("dom=css('span.foo a.baz')")I would be interested in hearing feedback from anyone who has a chance to use this technique!
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.

