Fork me on GitHub

23 Jun 2009

Scripting Plugin and Dependency Installation

Another quick script that I find quite useful, particularly on continuous integration servers is my Prepare.groovy script. It solves a couple of problems

  • Some plugins are not as well behaved as others on installation, for example the Functional Testing plugin automatically installs when test-app or run-app is installed but will then immediately crash with a ClassNotFoundException because the libraries it depends on are not on the classpath yet. Re-running the command will then work but if the commands are part of a CI build it's probably already bombed out and reported a broken build.
  • The Ivy plugin is great but test-app and run-app won't invoke its get-dependencies target to pull down libraries the way they will automatically install plugins.
  • Sometimes the grails command you want the build to execute is supplied by a plugin so there's no convenient way to run it directly from a brand new workspace because the plugin isn't installed yet.

The script simply ensures all plugins are installed and then invokes the Ivy plugin's get-dependencies target (only if the Ivy plugin is installed - it won't blow up on you if you don't use Ivy). At that point you should have a fully workable workspace and be able to run any grails command you like without your app complaining that some library or other isn't present.

18 Jun 2009

Joda Time Auto-Timestamping Issue on Grails 1.1.1

I've not upgraded most of my code to Grails 1.1.1 yet so I hadn't noticed this problem until it was brought to my attention by Manuel Vio on the grails-user mailing list.

I raised a bug a few days ago around the fact that GORM identifies Joda Time types (and presumably any non-default property type) as a one-to-one association. Up to now the only problem this caused me was that it means the Joda Time plugin has to do some slightly hacky tricks in the scaffolding templates to prevent crashes when Grails tries to render the properties as though they were associated domain instances only to find they have no id property. However, on Grails 1.1.1 the bug is causing a nasty failure on auto-timestamping.

Under Grails 1.1 you can use a Joda DateTime for an auto-timestamped fields:

DateTime dateCreated
DateTime lastUpdated

static mapping = {
dateCreated type: PersistentDateTime
lastUpdated type: PersistentDateTime
}

These behave exactly like the regular Date fields with those names, i.e. they're set automatically on save and update. In Grails 1.1.1 the same class will fail on save with a GroovyRuntimeException Could not find matching constructor for: java.lang.Object(java.lang.Long).

There is a (somewhat strange) workaround - declare the timestamped fields as non-lazy!

DateTime dateCreated
DateTime lastUpdated

static mapping = {
dateCreated type: PersistentDateTime, lazy: false
lastUpdated type: PersistentDateTime, lazy: false
}

Digging into the Grails code a little I found that association properties have their getter wrapped in a lazy-loading proxy. Since GORM thinks Joda Time properties are associations, this happens to them. The auto-timestamping code initialises the properties using property.getType().newInstance(System.currentTimeMillis()). Unfortunately, because property is actually the lazy-load proxy rather than the real property property.getType() returns Object.

15 Jun 2009

Checking for plugin updates

If you're anything like me you probably like to keep all your Grails plugins updated to the latest versions. It's quite easy to miss a release announcement and not realise there's a new version available. Although grails list-plugins will list out the available versions and what version you currently have installed it doesn't really highlight the plugins you could upgrade. I threw this script together this morning to do exactly that. It will simply check the plugin versions you have installed against all configured repositories and notify you of any that could be updated.

13 Jun 2009

Querying by Association Redux

A couple of months back I posted about the problems with criteria queries where you want results with a collection property that contains some value.

Last night I was reading through my new copy of Glen Smith and Peter Ledbrook's Grails In Action and my eye was caught by a particular example where they use aliases in a criteria query. Sure enough a quick test this morning confirms that this is the solution to the problem.

To recap. If I have these domain classes:

class Pirate {
String name
static belongsTo = Ship
static hasMany = [ships: Ship]
}

class Ship {
String name
static hasMany = [crew: Pirate]
}

and I want to query for all the Ships containing a particular Pirate I would probably try to do this:

def ships = Ship.withCriteria {
crew {
eq("name", "Blackbeard")
}
}

Unfortunately, while I end up with the correct Ship instances, each of their crew collections only contains the item(s) that matched the criteria regardless of any others that may actually exist.

Using an alias we can do this type of query without resorting to HQL:

def ships = Ship.withCriteria {
createAlias("crew", "c")
eq("c.name", "Blackbeard")
}

A complete test case that proves the point using the domain classes above is:

class PirateTests extends GroovyTestCase {

void setUp() {
Ship.withSession {session ->
def blackbeard = new Pirate(name: "Blackbeard")
def jack = new Pirate(name: "Calico Jack")
def bart = new Pirate(name: "Black Bart")
[blackbeard, jack, bart]*.save()

def ship1 = new Ship(name: "Queen Anne's Revenge")
ship1.addToCrew blackbeard
ship1.addToCrew jack

def ship2 = new Ship(name: "Royal Fortune")
ship2.addToCrew blackbeard
ship2.addToCrew bart

def ship3 = new Ship(name: "The Treasure")
ship3.addToCrew jack
ship3.addToCrew bart

[ship1, ship2, ship3]*.save()

session.flush()
session.clear()
}
}

void testQueryByAssoc() {
def ships = Ship.withCriteria {
crew {
eq("name", "Blackbeard")
}
order("name", "asc")
}

assertEquals 2, ships.size()
assertEquals "Queen Anne's Revenge, Royal Fortune", ships.name.join(", ")
assertEquals "Expected 2 crew but found ${ships[0].crew.name}", 2, ships[0].crew.size()
assertEquals "Expected 2 crew but found ${ships[1].crew.name}", 2, ships[1].crew.size()
}

void testQueryByAssocUsingAlias() {
def ships = Ship.withCriteria {
createAlias("crew", "c")
eq("c.name", "Blackbeard")
order("name", "asc")
}

assertEquals 2, ships.size()
assertEquals "Queen Anne's Revenge, Royal Fortune", ships.name.join(", ")
assertEquals "Expected 2 crew but found ${ships[0].crew.name}", 2, ships[0].crew.size()
assertEquals "Expected 2 crew but found ${ships[1].crew.name}", 2, ships[1].crew.size()
}
}

The first test fails as each Ship returned by the query only has Blackbeard in the crew despite the fact that they were created and saved with 2 crew members each. The second test retrieves the correct results.

Logging out the SQL generated by the Hibernate queries shows the difference in what it's doing under the hood. The first (incorrect) query is:

select * from ship
left outer join ship_crew on ship.id = ship_crew.ship_id
left outer join pirate on ship_crew.pirate_id = pirate.id
where pirate.name = ?
order by ship.name asc

The second (correct) query is:

select * from ship
inner join ship_crew on ship.id = ship_crew.ship_id
inner join pirate on ship_crew.pirate_id = pirate.id
where pirate.name = ?
order by ship.name asc

So the first query is using left outer joins and the second is using inner joins. Running those queries directly in SQuirreL returns basically the same result set so the discrepancy must be in how Hibernate treats the results. It seems Hibernate has populated the Ship instance and its crew collection after the first query and therefore considers the collection to be initialized, although actually the data in the result set was not the complete collection. In contrast, after the second query you can see the individual SQL select statements as the lazy-loading fires when the assertions are done, so Hibernate obviously only populated the root Ship instance from the query results and is treating the collection property as uninitialized.

Hacking on Grails scaffolding templates

Grails scaffolding is a fantastic mechanism for getting you up and running quickly. I love the fact that you can provide your own implementation of some controller actions or views and scaffolding will just fill in the gaps. That way you can start hand-crafting things when complexity increases past a certain point but still have Grails do a bunch of work for you.

I'd done some customising of scaffolding templates before for the Joda Time plugin but recently started playing with them again with a view to creating some I could re-use for future projects. Because scaffolding templates are not only used for dynamic views but also provide the basis of generated views that you go on to customise it's worth having a solid baseline. A couple of things I wanted to do were:

  1. Mark up create and edit forms without using tables
  2. Provide automatic indication of mandatory fields

I'm pretty happy with the result. This is how a standard create form now appears. The grab is from Safari 4 but the rendering is all but consistent across Firefox 3 on my Ubuntu box, Safari 4 on my Mac and even IE6, IE7, Google Chrome and Opera 9 on the Windows XP VirtualBox instances I use for cross-browser testing.

Forms Without Tables

Each form element is simply:

<div class="prop">
<label for="${p.name}">Property Name</label>
${renderEditor(p)}
</div>

Which is reasonable semantic markup. Styling it cross-browser took me a while (I know just enough CSS to make me dangerous) but with a few helpful pointers from our resident front-end guru Jeff I was able to achieve that with a lot less browser-specific tweaking than I would have thought would be necessary.

The necessary CSS is just:

.prop {
margin: 1em 0;
}
label {
display: inline-block;
margin-right: 1.5em;
text-align: right;
width: 8em;
}
input, select {
vertical-align: middle;
}
textarea {
vertical-align: top;
}

Making the label inline-block meant I can apply a width to it so all the fields will line up nicely but also keeps the label inline so I can then use vertical-align on the input to centre it on the text line of the label. The results are consistent cross-browser. Most solutions I've seen around the internet are horribly inconsistent between browsers (and operating systems with different font rendering) and often rely on nasty pixel-perfect margin and padding tweaks to try to align things nicely. That approach rapidly becomes a game of whack-a-mole as a tweak that fixes some alignment on IE will screw it up on Opera, fixing that will make Firefox do something odd, etc.

Automatically Indicating Mandatory Fields

A polite form should really indicate to the user what fields are mandatory and it turns out this isn't hard to achieve automatically in Grails scaffolded views. The scaffolding templates already use the constrained properties of the domain class to determine whether to display a form field for each property. It's a very small step to use the isNullable() and in the case of String properties isBlank() methods to decide whether to render a mandatory indicator.

I simply output a span with an asterisk inside the label then styled it with:

label {
/* other label properties as above */
position: relative;
}
label .mandatory {
color: #c00;
position: absolute;
right: -1.25em;
}

The absolute positioning takes the asterisk out of the flow of the page so the labels and inputs line up neatly regardless of whether there's an asterisk or not and the right: -1.25em shoves it over into the space of the label's right margin. Positioning the asterisk perfectly in between the label and the input is tricky and not reliable cross browser. On IE the asterisk is too far to the right.

I tried other techniques such as disabling the label's right margin when the asterisk is present and setting the asterisk's span to the exact same size the margin would have been. Unfortunately it seems 1.5em as an element width is not quite the same thing as 1.5em as a right margin so the alignment of the labels and inputs was thrown off. Absolute positioning is necessary to maintain that alignment which is far more important to the eye than pixel-perfect placement of the asterisk itself.

Source Code

Here's the source code. Any suggestions for improvements would be very welcome. I based the templates on Marcel Overdijk's excellent i18n-templates, the only differences are in the rendering of the form fields and the surrounding fieldset.

Something this exercise has driven home for me is that when it comes to cross-browser styling less is definitely more. Taking away everything, setting the font size consistently cross-browser, then gradually building up with the simplest markup and styling possible yields the best results.