Groovy, let me count the ways in which I love thee
Oh the wonder and the joy. I’ve been fixing some issues and adding features to the Grails Functional Testing plugin (now informally known as The G-Func) and had cause to marvel at some Groovy treats.
The problem: HtmlUnit, which the plugin uses for HTTP interactions, has an extensive hierarchy of classes representing page and form elements. There is however no way to indentify some of these as specific functional groups eg there are 4 different button types, which have no interface or ancestor that is not also shared by some other non-button classes.
So a little ugly logic is needed. For example when the plugin’s form wrapper uses Groovy dynamic property resolution to get a form field for you, it is now doing something like this:
private getFieldValue(f) {
// Note this switch is polymorphic, order of cases is IMPORTANT
switch (f.class) {
case BUTTON_CLASSES:
case HtmlFileInput.class:
return f // return the field object itself, not its value
case HtmlSelect.class:
return f.selected
case HtmlRadioButtonInput.class:
return f.checked
case HtmlCheckBoxInput.class:
return f.checked
case HtmlTextArea.class:
case HtmlInput.class:
return f.value
default:
throw new RuntimeException("Don't know how to get a value from form element of type [${f.class}]")
}
}
Now, what is special about this is:
- Groovy’s switch statement is very cool. It calls isCase(value) on the objects used in the case statements. That’s pretty basic Groovy stuff, but is still news to most Java developers.
- The use of BUTTON_CLASSES in the case is very cool. That property is a list of HtmlUnit classes that are “buttons” in conceptual terms. Groovy will call isCase on the list, which will return true if the list CONTAINS the switch value. That saved me 4 case lines and made my code more DRY as this check is also done elsewhere.
- The isCase implementation on Class added by the Groovy GDK is polymorphic. So the “case HtmlInput.class” actually catches any descendent of HtmlInput – of which there are several. This is also why the case BUTTON_CLASSES is at the top of the switch, as some of those classes extend HtmlInput and would be incorrectly caught by this HtmlInput clause.
Many people will no doubt say I can simplify the code above further – the “.class” are largely not necessary and I could merge the “return f.checked” cases. I may well do in future, but this is there for clarity at the moment





















6 Comments
Flokater
January 17, 2009I think switch in Java is kind of unusable. In groovy i use it day by day, eg. with my beloved Ranges.
Paul King
January 18, 2009Hi Marc, great to see some more testing with Groovy articles appearing.
Minor Grooviness suggestion: you should be able to drop the ‘.class’ suffix on f and the class names and you could merge the HtmlRadioButtonInput and HtmlCheckBoxInput branches.
Cheers, Paul.
Marc Palmer
January 18, 2009LOL Paul, nice joke
Paul King
January 19, 2009Hi Marc, I just meant this (try in GroovyConsole):
def things = ['hi', 3]
things.each { t ->
switch(t) {
case Integer: println ‘is a number’; break
case String: println ‘is a string’; break
}
}
Paul King
January 19, 2009I see your comment now. You have already thought of this. Forget my last comment. The other nice thing I like to use with switch is closures.
RJ Salicco
September 24, 2009Nice post. Groovy saves me time just about everyday at work!