Wednesday, November 25, 2009

Strong Groovy

Usually Groovy is thought of as a loose, dynamically typed language that is otherwise similar to Java. Given this, it would make sense to write in Groovy when dynamism is needed an write in Java when you need strong typing, etc. to avoid side effects. But a great differentiator for groovy over any other dynamic language running on the JVM is that it also has all of Java's support for Strong typing, Generics, immutable objects and the like. This allows Groovy a tremendous range using dynamism where it makes sense and locking it down where it makes sense to do that.

Recently I found myself looking for a solution for Value Lists for using in my HTML Select fields. Initially I went for quick and dirty and created a utility class (a singleton) with a bunch of "value" lists. Literally lists of NameValue objects with a corresponding java class like:


public class NameValue {
private String name;
private String value;

public NameValue(String name, String value) {
this.setName(name);
this.setValue(value);
}

@Override
public String toString() {
return getValue();
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getValue() {
return value;
}

public void setValue(String value) {
this.value = value;
}
}


I'm not sure why I used Java for this considering it was a grails project, but the class would have read better in groovy:


class NameValue {
String name, value

@Override
public String toString() {
return this.getValue();
}
}


Then I used my Singleton class to populate the lists as so:


public class ValueLists {
private static ValueLists ourInstance = new ValueLists();

public static ValueLists getInstance() {
return ourInstance;
}

private List approvals = new ArrayList();

public List getApprovals() {
return this.approvals;
}

approvals.add(new NameValue("1", "Yes"));
approvals.add(new NameValue("0", "No"));
approvals.add(new NameValue("2", "Exempt"));
}


While we're at it.... why not redo this class in groovy:


class ValueLists {
private static ValueLists ourInstance = new ValueLists();

public static ValueLists getInstance() {
return ourInstance;
}

private List approvals = [
new NameValue(name: "1", value: "Yes"),
new NameValue(name: "0", value: "No"),
new NameValue(name: "2", value: "Exempt")
]
}


Now I can use my Value Lists in my grails app like so:


<g:select name="approval" from="${ValueLists.instance.approvals}" optionkey="name"/>


Simple enough but it occurs to me that the ValueLists ought to be immutable as the lists should never change. It would then look like:


@immutable final class ValueLists {
private static ValueLists ourInstance = new ValueLists();

public static ValueLists getInstance() {
return ourInstance;
}

private List approvals = [
new NameValue(name: "1", value: "Yes"),
new NameValue(name: "0", value: "No"),
new NameValue(name: "2", value: "Exempt")
]
}


"approvals" (and any other properties) is now treated as private final with a getter. So my unwary teammates cannot override it. In addition, "approvals" is wrapped by an immutable wrapper class so my teammates can't get the list of NameValues and change it.

Of course if you've been working with Java 1.5 or newer for any significant amount of time it probably would have occurred to you that you could have used java's language support for enums. Well, no need to drop down to Java for this. My new Groovy Object is as follows(Approval.groovy):


enum Approval{
Yes("1", "Yes"),
No("0", "No"),
Exempt("2", "Exempt")

final String value
final String key

Approval(String key, String value) {
this.value = value
this.key = key
}

String toString() {
value
}
}


Now following this pattern I can code up all my grails selects as follows:


<g:select name="approval" from="${Approval}" optionkey="key" optionvalue="value"/>


The point is that Groovy is a Strongly typed language as well as it is a Dynamically typed language.

Wednesday, October 21, 2009

SacGRU (Sacramento Groovy Users) first meeting tomorrow

The Sacramento Groovy Users will be having their first meeting tomorrow at Quilogy. Please come by and meet other enthusiastic Groovy/Grails/Griffon/Gradle/GPars users.

Quilogy
2880 Gateway Oaks Drive, Suite 350
Sacramento, CA 95833

6:00 - 9:00 P.M.

Hope to see you there!

Thursday, June 4, 2009

Integration Testing Grails Controllers

If you are planning on running integration tests on your Grails controllers it would be good to know how to test your controller regardless of whether it simply returns the model or uses the render method.

When your controller returns a model you can simply test the return type.

Given:

def show = {
def bookInstance= Book.get( params.id )
return [ bookInstance: bookInstance] }
}


You test it by:

def model = myController.show()
assertNotNull model.bookInstance

or some such.

If you use the render method in your controller then you would use the ModelAndView object in your controller.

Given:

def save = {
def bookInstance = Book.get(params.id)
render(view:'create',model: [ bookInstance : bookInstance ])
}

You can test it as follows:

bookController.save()
assertNotNull bookController.modelAndView.model.bookInstance

There is one nasty caveat to the render method, and that is if you are rendering a template instead of a view. This is common when you are doing AJAX type calls that only return a partial page. The problem is that Grails will not populate the modelAndView map at all. Nor does render provide a return type.

The answer came from the following mailing list posting:

http://www.nabble.com/Testing-Controller-with-render(template:....)-td18757149.html

Essentially you need to alter the behavior of the render method. You can do this in the setup as follows:

def renderMap

protected void setUp() {
super.setUp()
BookController.metaClass.render = { Map map ->
renderMap = map
}
}


Then Given:


def bookSummary = {
def bookInstance = Book.get(params.id)
render(template: "bookSummary", model: [ bookInstance : bookInstance ])
}


And then you test your model values as follows:

bookController.bookSummary()
assertNotNull renderMap.model.bookInstance

I hope this is helpful.

Happy Grailing!

Thursday, May 7, 2009

Intellij 8.1.1 out with Grails 1.1 support

Intellij has reclaimed it's crown as uncontested King of Groovy/Grails IDEs with the release of 8.1.1. As many of you know, the release of Grails 1.1 introduced a number of improvements, in particular changes to dependency management and plugins, the testing plugin integration, etc. While all these improvements were great, the fantastic support for Groovy/Grails in IDEA broke.

Now with release 8.1.1 you can expect all the IntelliGrails goodness to return. As one who was using the EAP to get Grails 1.1 support I'm also happy to report that the Intellij team was highly responsive to our bug reports in particular the inability to debug integration tests. It all seems to be working in the last EAP and I'm downloading the Gold release now.

If I notice anything interesting I'll post again with my experiences.

Tuesday, March 31, 2009

Executing command line scripts from Groovy on Windows

Today I had the need to create a number of dependencies within my local Maven repository (I know it's a hack you Maven purists, back off). I decided that I would use Groovy to loop over the jars in the lib directory and create the a dependency for each file. Groovyists know how easy this is:

new File('.').eachFile{
//do something
}


And of course I was aware that on Windows you have to use a "cmd /c" prior to your executable. So my final was going to look like this:


new File('.').eachFile{
groupId = it.name.substring(0, it.name.size() - 4)
"cmd /c mvn install:install-file -DgroupId=blahzy.blah-DartifactId=${groupId} -Dversion=9.9.9 -Dpackaging=jar -Dfile=${it.name}".execute().text
}


Seems appropriately short and succinct for my groovy instincts to feel okay with it. Only problem is that it didn't work. When I would run it the console would freeze and I had no idea what was going on. After reading through some of the groovy documentation online I found out that if the output is too much the Windows process will just freeze. Luckily there was a documented "hack" to solve the issue. My final script:


new File('.').eachFile{
groupId = it.name.substring(0, it.name.size() - 4)
thisCommand = "cmd /c mvn install:install-file -DgroupId=blahzy.blah-DartifactId=${groupId} -Dversion=9.9.9 -Dpackaging=jar -Dfile=${it.name}"
proc = thisCommand.execute()
proc.consumeProcessOutput()
}


So I don't get any of the output but it worked so who am I to complain.

Monkey Search