Archive for January, 2008

Undocumented goodies of Grails - Part 1

Tuesday, January 29th, 2008

Working with Grails you can often discover exciting features from time to time. And even better (or worse?), some of them are undocumented, which feels kind of like treasure hunting.

Lately I discovered this gem of feature which is left out of the latest documentation. You can use a closure with the <g:select> tag to fully customize the displayed values of your options list!

It works like this. For example you have a list of values indicating minutes, e.g. 15, 30, 60, 120, … You want to give the list to <g:select>, but you don’t want to simply display the bunch of numbers as-is because that’s ugly. You want the minute values to be displayed as “15 Minutes”, “30 Minutes”, “1 Hour”, “2 Hours”, etc.

How would you do this? Custom tag lib? It sure works, but definitely will cost you more than a one-liner. But using a closure to supply the formatting logics directly to <g:select>, this IS a one-liner!

<g:select from='${minutesList}' optionValue='${{it<60?("$it Minutes"):(it>60?("${it/60} Hours"):("${it/60} Hour"))}}' name='prettyList'/>

That’s it! The closure supplied to optionValue takes the List given by the “from” attribute, and iterates the List. Now your controller can take the raw minutes values while the front end displays human friendly minutes and hours reading.

By reading the <g:select> source code, you will see that the attribute “optionKey” can take a closure, too. What clever use of this can you think of now?

Update: I think part of the reason this is undocumented could be that this would encourage bad habits of littering the views with too much logic. So use it wisely. I recommend only using this for simple and clear one-liners.

Mini guide to rendering JSON with Grails

Sunday, January 13th, 2008

Grails has built-in support for a JSON building DSL, which, together with the render controller dynamic method, makes rendering JSON responses an enjoyable job. But there seems to be a lack of consolidated information in the official documentation to clarify all the bits about getting anything you want in JSON. So here’s my little mini guide to share with you.

Ground Rules

As the JSON spec reads,

JSON is built on two structures:

  • A collection of name/value pairs. In various languages, this is realized as an object, record, struct, dictionary, hash table, keyed list, or associative array.
  • An ordered list of values. In most languages, this is realized as an array, vector, list, or sequence.

So there are only two rules for rendering JSON with Grails.

1. To render a collection of name/value pairs (an object), use the method call syntax.

e.g.

render(contentType:'text/json'){
	pair(name:'value')
}

Will be rendered as

{"pair":{"name":"value"}}

2. To render an array of values, use a closure

e.g.

render(contentType:'text/json'){
	collection{
		pair(name:'value')
		pair(name:'value1')
	}
}

Will be rendered as

{collection:[{"name":"value"},{"name":"value1"}]}

Anything inside the collection closure becomes the values of the array. And because of this, the method name “pair” has no place to appear in the rendered array.

Putting It to Work

Here’s an example putting the two rules together.

render(contentType:'text/json'){
	studio(name:'Pixar',website:'pixar.com')
	films{
		film(title:'Toy Story',year:'1995')
		film(title:'Monsters, Inc.',year:'2001')
		film(title:'Finding Nemo',year:'2003')
	}
}

The result JSON will be

{"studio":{"name":"Pixar","website":"pixar.com"},
"films":[
{"title":"Toy Story","year":"1995"},
{"title":"Monsters, Inc.","year":"2001"},
{"title":"Finding Nemo","year":"2003"}
]}

When DSL is Not Enough

But there’s a gotcha about the current JSON Builder DSL to keep in mind. As of 1.0 RC3, You can have objects inside an array, but not an array inside an object (except the JSON object itself).

For example, I want a JSON structure like this.

{"object":{"collection":[{"name":"value1"},{"name":"value2"}]}}

I may write something like this,

render(contentType:'text/json'){
	object(collection{
		item(name:'value1')
		item(name:'value2')
	})
}

Although it’s syntactically correct, you will get a runtime exception of

java.lang.IllegalArgumentException: JSON Builder: not implemented
	at grails.util.JSonBuilder.createNode(JSonBuilder.java:121)
...

Oh, maybe I made a mistake, I think. The closure is not a key/value pair there. And I change the code like this

render(contentType:'text/json'){
	object(collection:{
		item(name:'value1')
		item(name:'value2')
	})
}

This looks better. Does it work? Nope. It’s not what you’d expect.

{"object":{"collection":"DummyController$_closure15_closure27_closure28@4af40c"}}

This can’t be right. Then how about

render(contentType:'text/json'){
	object(collection:collection{
		item(name:'value1')
		item(name:'value2')
	})
}

Oddly, this will be rendered as

{"collection":[{"name":"value1"},{"name":"value2"}],"object":{"collection":1}}

The Almighty JSON converter

So is there any workaround, when JSON Builder DSL fails you? Yes! You can always turn to the JSON converter. Construct a temporary Map to contain the data, and use the converter to render the map as a whole.

To correctly render the JSON data in the previous section, you can use the JSON converter this way. In your controller, use the following code.

import grails.converters.*
...
def jsonMethod = {
	...
	def json = [object:[collection:[[name:'value1'],[name:'value2']]]]
	render json as JSON
}

The result JSON will be exactly what I want

{"object":{"collection":[{"name":"value1"},{"name":"value2"}]}}

You can render any object using the JSON converter. And the results are pretty predictable.

Performance-wise, I’m not sure if there’s any difference or anyone has done any benchmark yet. So I’d say that it’s really your call which way to make your JSON. The converter doesn’t look as sexy as the DSL, but it sure works great. I may just choose either one depending on my mood:)

Grails: Sending email using Ant with GMail SMTP server

Thursday, January 10th, 2008

SMTP is one service I don’t want to burden my little site with. So I’m trying to send emails using the Gmail SMTP server.

Actually, sending emails with Grails is a breeze. There are different ways but I find that using the Ant mail task is the most effortless one. Thanks to the excellent demonstration by Glen Smith with the GroovyBlogs code, I could get started in a fraction of time. But to successfully use the GMail SMTP service, there are a few things to pay attention to.

1. Be sure to copy necessary jars to your grails-app/lib

The required jars include:

*If you are on Java 1.5 or earlier, you need the additional activation.jar. Since I’m using Java 6, it’s included in the JDK and I don’t need a copy in my lib.

2. GMail SMTP settings

This has literally cost me some hours so I hope it’s helpful to you. I at first searched for a set working settings and it turns out port 587 is the working one (for Rails). I did so but hit into mysterious exceptions with SSL.

: Problem while sending mime mail:
at groovy.util.AntBuilder.nodeCompleted(AntBuilder.java:199)
...
Caused by: javax.mail.MessagingException: Exception reading response;
nested exception is:
javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?
...

This lead me to the wrong direction and I spent some time investigating if there’s anything wrong with my config and Ant dealing with SMTP behind SSL/TLS. But finally, it turns out that port 587 was NOT being friendly to Ant over SSL. Use port 465 and it’s all good! (which is the opposite situation with Rails)

A little summary

So the complete config for GMail looks like this. (As written in Config.groovy)

mail{
  host="smtp.gmail.com"
  port="465"
  ssl="on"
  user="your.addr@gmail.com"
  password="password"
}

Use these as the params for the Ant mail task. To glue things together with Grails, you just need to

  1. Put the Ant params in Config.groovy so that they can be easily modified later.
  2. Create a service class for sending emails. e.g. MailService.groovy. Then in the service method, use AntBuilder’s DSL to create the mail task. It should look something like
    import org.codehaus.groovy.grails.commons.ConfigurationHolder as C
    ...
    new AntBuilder().mail(
      mailhost:C.config.mail.host,
      mailport:C.config.mail.port,
      ssl:C.config.mail.ssl,
      user:C.config.mail.user,
      password:C.config.mail.password,
      subject:msgSubject
    ){
      from(address:C.config.mail.reply.name)
      to(address:toAddr)
      message(mimetype:"text/html", content)
    }

That’s pretty neat, eh? If you feel like getting a peek at some working code, you can grab the GroovyBlogs source and do the modifications to talk with GMail in minutes.