<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-9390811</id><updated>2011-12-02T03:50:36.688Z</updated><category term='acegi'/><category term='hibernate'/><category term='i18n'/><category term='continuous integration'/><category term='javascript'/><category term='grails scripts'/><category term='asynchronous'/><category term='html5'/><category term='spock'/><category term='immutable'/><category term='grails upgrade'/><category term='events'/><category term='selenium'/><category term='grails controllers'/><category term='hudson'/><category term='ux'/><category term='intellij'/><category term='gmock'/><category term='gorm'/><category term='chrome'/><category term='geb'/><category term='scaffolding'/><category term='firefox'/><category term='jquery'/><category term='gradle'/><category term='grails plugins'/><category term='css'/><category term='ivy'/><category term='webkit'/><category term='junit4'/><category term='git'/><category term='groovy'/><category term='functional testing'/><category term='resources'/><category term='spring'/><category term='joda time'/><category term='forms'/><category term='criteria queries'/><category term='ggug'/><category term='ubuntu'/><category term='progressive enhancement'/><category term='caching'/><category term='testing'/><category term='webflow'/><category term='opera'/><category term='json'/><category term='safari'/><category term='data binding'/><title type='text'>Ad-Hockery</title><subtitle type='html'>ad-hockery: /ad·hok'@r·ee/, n.

Gratuitous assumptions... which lead to the appearance of semi-intelligent behavior but are in fact entirely arbitrary.

[Jargon File]</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>62</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-9390811.post-7590752790929808922</id><published>2011-11-29T00:11:00.001Z</published><updated>2011-11-29T00:12:01.253Z</updated><title type='text'>This blog has moved</title><content type='html'>Ad-Hockery is no longer updated at this location. Please redirect bookmarks to &lt;a href="http://adhockery.github.com/"&gt;adhockery.github.com&lt;/a&gt; for more awesome content.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-7590752790929808922?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/7590752790929808922/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=7590752790929808922' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/7590752790929808922'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/7590752790929808922'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2011/11/this-blog-has-moved.html' title='This blog has moved'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-4071817607226154436</id><published>2011-11-24T00:59:00.001Z</published><updated>2011-11-24T09:26:43.706Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='functional testing'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='selenium'/><category scheme='http://www.blogger.com/atom/ns#' term='geb'/><title type='text'>Fear &amp; loathing in functional testing land</title><content type='html'>&lt;p&gt;As projects grow the two things I&amp;#8217;ve repeatedly found to be particularly painful have been functional testing and data fixtures. I might write up some thoughts on data fixtures another time but what follows is a brain-dump of my troubled relationship with functional testing.&lt;/p&gt;&lt;p&gt;&lt;em&gt;Disclaimers:&lt;/em&gt; I have more questions than answers and I&amp;#8217;m completely open to the idea that &lt;em&gt;I&amp;#8217;m doing it all wrong&lt;/em&gt;. I&amp;#8217;m not trying to diss any tool or technique here. I have spent a lot of time over the last few years writing functional test coverage so I think I at least have some perspective on the issues if no clue how to solve them.&lt;/p&gt;&lt;p&gt;When I say functional testing I mean in the &lt;a href="http://grails.org/doc/latest/guide/9.%20Testing.html#9.3%20Functional%20Testing"&gt;Grails sense of an &lt;em&gt;end-to-end&lt;/em&gt; test via the browser&lt;/a&gt;. Some people are quite resistant to writing such tests and whilst I agree that as much testing as possible should be done at as low a level as possible there are certain things that really only can be tested in that way. I&amp;#8217;m also a big fan of the &lt;a href="http://www.growing-object-oriented-software.com/" title="Growing Object-Oriented Software, Guided By Tests"&gt;GOOS&lt;/a&gt; approach of working outside in; starting with a (failing) functional test that defines the desired behaviour in a user-centric way and building in to the low-level implementation with its unit tests then back out to watch the original end-to-end test (hopefully) pass.&lt;/p&gt;&lt;h4 id="why_is_functional_testing_difficult"&gt;Why is functional testing difficult?&lt;/h4&gt;&lt;h5 id="test_development_cadence"&gt;Test development cadence&lt;/h5&gt;&lt;p&gt;The main issue I find when constructing functional tests is what I&amp;#8217;ll call the &lt;em&gt;test development cadence&lt;/em&gt;; that is the time it takes to go round the loop (and sub-loops) of&lt;/p&gt;&lt;ol&gt;&lt;li&gt;write a bit of test&lt;/li&gt;&lt;li&gt;watch it fail&lt;/li&gt;&lt;li&gt;write some code to make it work&lt;/li&gt;&lt;li&gt;watch it still fail&lt;/li&gt;&lt;li&gt;figure out if your expectation is wrong or your code doesn&amp;#8217;t work&lt;/li&gt;&lt;li&gt;fix it&lt;/li&gt;&lt;li&gt;repeat last 3 steps &lt;em&gt;n&lt;/em&gt; times&lt;/li&gt;&lt;li&gt;watch it pass&lt;/li&gt;&lt;li&gt;&lt;a href="http://s3.amazonaws.com/kym-assets/entries/icons/original/000/006/548/211092_242669842430795_4056741_n.jpg?1313963401"&gt;celebrate&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;With a unit test that time is typically fast, a keystroke in an IDE and the results are available in at most a couple of seconds. Functional tests are considerably slower. Even assuming you can optimise so that the application is running and you can run the test from an IDE then Selenium has to start up a browser instance, queries execute, views need to render, etc. In the worst case you&amp;#8217;re switching to the terminal and using &lt;code&gt;grails test-app functional: Blarg&lt;/code&gt; or equivalent then waiting for the webapp to start up before the test can even start to run and shut down again before the report is generated.&lt;/p&gt;&lt;p&gt;A slow test development cadence leads to distraction (checking &lt;em&gt;Twitter&lt;/em&gt;, making coffee, getting drawn into a discussion of the finer points of mixing an &lt;em&gt;old fashioned&lt;/em&gt;, etc.) and distraction leads to context-switching which slows things still further.&lt;/p&gt;&lt;h5 id="test_diagnostics"&gt;Test diagnostics&lt;/h5&gt;&lt;p&gt;&lt;em&gt;GOOS&lt;/em&gt; makes a great point about the importance of test diagnostics suggesting that the &lt;a href="http://en.wikipedia.org/wiki/Test-driven_development" title="Test-driven development"&gt;&lt;em&gt;TDD&lt;/em&gt;&lt;/a&gt; mantra of &lt;a href="http://jamesshore.com/Blog/Red-Green-Refactor.html"&gt;&lt;em&gt;&amp;#8220;red, green, refactor&amp;#8221;&lt;/em&gt;&lt;/a&gt; should be replaced with &lt;em&gt;&amp;#8220;red, &lt;strong&gt;decent diagnostics&lt;/strong&gt;, green, refactor&amp;#8221;&lt;/em&gt;. When a test breaks, especially one someone else wrote (or that I wrote more than a week ago and have consequently lost all recollection of), I want to be able to see what&amp;#8217;s broken without re-running the test with added logging or resorting to a debugger. Testing further from the browser hurts diagnostics as you can&amp;#8217;t &lt;em&gt;see&lt;/em&gt; what&amp;#8217;s not working and so have to rely solely on the quality of your assertion output. That&amp;#8217;s not an easy thing to get right. Geb&amp;#8217;s output when a &lt;code&gt;waitFor&lt;/code&gt; condition fails is just &lt;code&gt;Condition did not pass in x seconds&lt;/code&gt;. Even with direct assertions and nice &lt;a href="http://docs.codehaus.org/display/GROOVY/Groovy+1.7+release+notes#Groovy1.7releasenotes-PowerAsserts" title="Groovy Power Asserts"&gt;power assert&lt;/a&gt; output its not always clear whether the functionality didn&amp;#8217;t work or the expectation is incorrect. Selenese is by no means great in this regard (a humble &lt;code&gt;Condition timed out&lt;/code&gt; isn&amp;#8217;t much help) but at least you can step back with the Selenium IDE and watch the damn thing not working much more easily.&lt;/p&gt;&lt;p&gt;Bad test diagnostics coupled with a slow test development cadence make for a horrible experience.&lt;/p&gt;&lt;h4 id="the_quest_for_the_functional_testing_holy_grail"&gt;The quest for the functional testing holy grail&lt;/h4&gt;&lt;p&gt;The &lt;em&gt;most productive&lt;/em&gt; I&amp;#8217;ve ever been when writing functional tests has been when using &lt;a href="http://seleniumhq.org/projects/ide/"&gt;Selenium IDE&lt;/a&gt;. That&amp;#8217;s quite an admission for someone who&amp;#8217;s spent a considerable amount of time &amp;amp; energy over the last few years trying to find or build something better!&lt;/p&gt;&lt;p&gt;The test development cadence is fast. Really fast. When you&amp;#8217;re writing tests with Selenium IDE (and I do mean &lt;strong&gt;write&lt;/strong&gt; them, I&amp;#8217;ve almost never used the recording functionality) the app is running, the browser is running and you can execute the test, a portion of the test or an individual command very quickly. You can step through the test, set breakpoints, etc. When using a framework like Grails that lets you make changes to the app without restarting you can rock along pretty rapidly.&lt;/p&gt;&lt;p&gt;That said, the downsides are not inconsiderable:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Abstraction is typically poor; you&amp;#8217;re dealing with fine details of page structure (DOM element ids, CSS selectors) and copy &amp;#8216;n pasting sequences of commands that would in a sane world be defined as functions or macros. You &lt;em&gt;can&lt;/em&gt; write custom JavaScript commands but with considerable limitations such as the fact that any &lt;em&gt;wait for x&lt;/em&gt; step must be the last thing the command does. Lack of abstraction means lack of maintainability. As the project goes on any change in page rendering probably means picking apart a bunch of tests that fail not because the functionality they are testing has stopped working but because the implementation of that functionality has changed.&lt;/li&gt;&lt;li&gt;Atomicity is difficult. Because each test probably requires a few lines of setup it&amp;#8217;s tempting for developers to add new assertions to an existing test. This violates the principle of having a single (logical) assertion per test. Part of the problem I think is that with Java, Groovy, Ruby, etc. each &lt;em&gt;file&lt;/em&gt; can contain multiple tests whereas with Selenese each file is a single test script. The right thing to do is to have lots of small Selenese test files but it&amp;#8217;s tempting to fall into the trap of munging tests together into the testing equivalent of a &lt;a href="http://en.wikipedia.org/wiki/Run-on_sentence"&gt;run-on sentence&lt;/a&gt;. One of the worst side-effects of this is that as a test suite grows it becomes really hard to identify &lt;em&gt;where&lt;/em&gt; certain features are tested and to find redundancy or obsolete tests.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Despite these significant failings &lt;em&gt;writing&lt;/em&gt; tests in Selenium IDE is very effective. Maintaining a suite of such tests is another matter. Working on a long-running project the failings of Selenese tests start to increase logarithmically. The reason I created the &lt;a href="http://robfletcher.github.com/grails-selenium-rc/docs/manual/index.html"&gt;Grails Selenium RC plugin&lt;/a&gt; was to try to build something I could use in future projects that would combat the failings of Selenese. I wanted to use a &amp;#8216;real&amp;#8217; language with selection and iteration and to be able to build a robust abstraction so that tests are not dealing with the fine details of page markup. &lt;a href="http://www.gebish.org/"&gt;Geb&lt;/a&gt; is another step along this road. It provides a nice way of defining page objects and modules and handles things like tracking which page class is the &amp;#8216;current&amp;#8217; one and how and when that should change.&lt;/p&gt;&lt;h4 id="what_do_i_want_from_a_functional_testing_tool_language"&gt;What do I want from a functional testing tool/language?&lt;/h4&gt;&lt;p&gt;I&amp;#8217;m convinced that the goal of writing tests in the same language as the application is a pretty vapid one. Working inside one&amp;#8217;s comfort zone is all very well but too many times I&amp;#8217;ve seen things tested using Selenium or Geb that would be better tested with a unit-level JavaScript test. I&amp;#8217;m guilty of this myself. I&amp;#8217;m a better Groovy coder than I am a JavaScript coder so it&amp;#8217;s easy initially to break out a new Geb spec than a new Jasmine spec. Functional testing tools are &lt;em&gt;really bad&lt;/em&gt; at testing fine-grained JavaScript behaviour, though. These sort of tests are really flaky, false negatives are a fact of life. They&amp;#8217;re wastefully slow as well. JavaScript unit tests are &lt;em&gt;fast&lt;/em&gt;, faster than Groovy unit tests. As a Grails developer I&amp;#8217;ve looked enviously at how fast tests run in Rails apps but that&amp;#8217;s nothing compared to watching a couple of hundred &lt;a href="http://pivotal.github.com/jasmine/"&gt;Jasmine&lt;/a&gt; tests run in under a second. To get back to the point, I have no problem with writing my functional tests in something other than Groovy if I can hit my goals of productivity and maintainability.&lt;/p&gt;&lt;p&gt;I was at one time convinced that the ability to use loops and conditional statements in Groovy made it a more suitable testing language than Selenese but honestly, how often are such constructs really required for tests? The The single most essential thing for a maintainable suite of functional tests is the ability to create a decent abstraction. Without that you&amp;#8217;ll be building brittle tests that fail when the implementation changes 100 times more often than they fail because the functionality they&amp;#8217;re testing is actually broken.&lt;/p&gt;&lt;h4 id="abstraction_is_key"&gt;Abstraction is key&lt;/h4&gt;&lt;p&gt;The abstraction layer needs to be powerful but simple. I&amp;#8217;ve seen test suites crippled by badly written page object models and I&amp;#8217;m starting to feel that the whole idea is too formalized. Building Geb content definitions with deeply nested layers of &lt;code&gt;Module&lt;/code&gt; types is time consuming &amp;amp; difficult. With Selenium RC there&amp;#8217;s not even the page transition logic Geb provides so you end up having to write that as well (probably getting it wrong or implementing it in several different ways in different places).&lt;/p&gt;&lt;p&gt;I can&amp;#8217;t help thinking the page object model approach is coming at the problem from the wrong angle. Instead of abstracting the UI shouldn&amp;#8217;t we be abstracting the behaviour? After all the goal is to have tests that describe how users interact with the application rather than how the various components that make up the application relate to one another. I&amp;#8217;d rather have a rusty toolbox of lightweight macros and UI module definitions than a glittering palace of a page component model that I find awkward to use, extend or change. The abstraction has to be there - when I change the implementation I don&amp;#8217;t want to spend half a day finding and fixing 100 subtly different CSS selectors scattered throughout the tests - but I don&amp;#8217;t think it has to be particularly deep.&lt;/p&gt;&lt;h4 id="where_do_i_go_from_here"&gt;Where do I go from here?&lt;/h4&gt;&lt;h5 id="a_better_selenese"&gt;A better Selenese?&lt;/h5&gt;&lt;p&gt;An interesting possibility for creating better Selenese tests is the &lt;a href="http://ttwhy.org/code/ui-doc.html"&gt;UI-Element extension library&lt;/a&gt; that allows a UI abstraction layer to be built on top of Selenese. It also introduces the concept of &lt;em&gt;rollup rules&lt;/em&gt; (paramaterized macros) that are a more powerful way of abstracting command sequences than custom Selenese commands. From what I&amp;#8217;ve seen the tool support in Selenium IDE looks impressive too. I need an opportunity to use &lt;em&gt;UI-Element&lt;/em&gt; seriously but it certainly appears promising.&lt;/p&gt;&lt;p&gt;The most impressive Selenium extension I&amp;#8217;ve seen is Steve Cresswell&amp;#8217;s &lt;a href="https://github.com/energizedwork/selenium-ide-nle"&gt;Natural Language Extensions&lt;/a&gt; that layers something like &lt;a href="http://jbehave.org/"&gt;JBehave&lt;/a&gt;&amp;#8217;s feature definition language on top of Selenese. &lt;a href="http://energizedwork.com/"&gt;Energized Work&lt;/a&gt; used this on a couple of projects (unfortunately not ones I was involved with) and I&amp;#8217;ve heard great stories of how it enabled really rich cooperation between developers, QA and project stakeholders. I was pleasantly surprised with how simple the underlying code appeared to be given the radical difference in the test language.&lt;/p&gt;&lt;h5 id="other_options"&gt;Other options?&lt;/h5&gt;&lt;p&gt;The tools I really need to look into are:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://cukes.info/"&gt;Cucumber&lt;/a&gt; which syntactically looks like the answer to my prayers. I want to see how fast the test development cadence is. Since there&amp;#8217;s now &lt;a href="https://github.com/cucumber/cucumber-jvm/"&gt;a pure JVM implementation&lt;/a&gt; I really have no excuse for not getting up to speed with it pronto.&lt;/li&gt;&lt;li&gt;&lt;a href="http://funcunit.com/"&gt;FuncUnit&lt;/a&gt; is much lower level and I&amp;#8217;m not sure how easy it would be to build an effective abstraction layer that kept the tests readable and maintainable but it&amp;#8217;s fast and runs right in the browser which are potentially compelling advantages.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-4071817607226154436?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/4071817607226154436/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=4071817607226154436' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/4071817607226154436'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/4071817607226154436'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2011/11/fear-loathing-in-functional-testing.html' title='Fear &amp; loathing in functional testing land'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-2675308762255116633</id><published>2011-08-26T17:19:00.001+01:00</published><updated>2011-08-26T17:21:07.980+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails controllers'/><title type='text'>Grails Gotcha: Beware HEAD requests when rendering binary output in controllers</title><content type='html'>&lt;p&gt;Although most Grails controllers render HTML, JSON or XML output it is possible to use them to render binary data as well. We use a controller to render images uploaded by editors into our content management interface. The theory is simple enough, instead of using the &lt;code&gt;render&lt;/code&gt; dynamic method or returning a &lt;em&gt;model&lt;/em&gt; the controller action just writes bytes directly to the HTTP response stream. Our action looked something like this:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;def show = {&lt;br /&gt;    def image = Image.read(params.id)&lt;br /&gt;    if (image) {&lt;br /&gt;        response.contentType = image.contentType&lt;br /&gt;        response.outputStream.withStream { stream -&amp;gt;&lt;br /&gt;            stream &amp;lt;&amp;lt; image.bytes&lt;br /&gt;        }&lt;br /&gt;    } else {&lt;br /&gt;        response.sendError SC_NOT_FOUND&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This seemed to work well enough. However when writing a test I noticed an odd thing. I was using &lt;a href="http://groovy.codehaus.org/modules/http-builder/doc/rest.html"&gt;RESTClient&lt;/a&gt; to scrape resource URLs out of and make a &lt;em&gt;HEAD&lt;/em&gt; request against them to ensure the URLs were valid. Javascript and CSS files were working fine but all the non-static images in the page were getting 404s. Initially I suspected a data setup problem and spent some time ensuring my test was setting data up properly. It was only once I put some debug logging in the controller action that I saw that the controller &lt;em&gt;was&lt;/em&gt; actually loading images. The 404 was not coming from the &lt;em&gt;else&lt;/em&gt; block in the action as I initially assumed. I tried changing the &lt;em&gt;RESTClient&lt;/em&gt; call from &lt;em&gt;head&lt;/em&gt; to &lt;em&gt;get&lt;/em&gt; and suddenly the image URLs started working!&lt;/p&gt;&lt;p&gt;Once I did that I realised what the problem was. An HTTP &lt;em&gt;HEAD&lt;/em&gt; request does not expect a response, in fact a server receiving a &lt;em&gt;HEAD&lt;/em&gt; request &lt;a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.4"&gt;&lt;em&gt;must not&lt;/em&gt; return a response&lt;/a&gt;. The response stream that our controller action is writing to is, when the request method is &lt;em&gt;HEAD&lt;/em&gt;, actually a no-op stream. When the action completes Grails checks to see if anything has been committed to the response stream and since it has not assumes that we want to render a view by convention. You can probably see where this is going now. The convention is that the request gets forwarded to &lt;code&gt;grails-app/views/&amp;lt;controller&amp;gt;/&amp;lt;action&amp;gt;.gsp&lt;/code&gt; which of course does not exist. The forwarded request sets a response code of &lt;em&gt;404&lt;/em&gt; because there is no GSP!&lt;/p&gt;&lt;p&gt;We caught this bug in our app completely by accident but it could actually have been quite serious. Caching proxies and CDNs may well use a &lt;em&gt;HEAD&lt;/em&gt; request to revalidate content and on getting a &lt;em&gt;404&lt;/em&gt; assume that the URL is no longer valid. If the &lt;em&gt;404&lt;/em&gt; response itself then gets cached we could get broken images on our site because the CDN tells the client browser there's nothing there.&lt;/p&gt;&lt;p&gt;The solution is simple enough. I changed the controller action to simply set a &lt;em&gt;200&lt;/em&gt; response code when it gets a &lt;em&gt;HEAD&lt;/em&gt; request for a valid image:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;def show = {&lt;br /&gt;    def image = Image.read(params.id)&lt;br /&gt;    if (image) {&lt;br /&gt;        if (request.method == "HEAD") {&lt;br /&gt;            render SC_OK&lt;br /&gt;        } else {&lt;br /&gt;            response.contentType = image.contentType&lt;br /&gt;            response.outputStream.withStream { stream -&amp;gt;&lt;br /&gt;                stream &amp;lt;&amp;lt; image.bytes&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    } else {&lt;br /&gt;        response.sendError SC_NOT_FOUND&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A neater solution might be to use Grails&amp;#8217; support for &lt;a href="http://grails.org/doc/latest/guide/6.%20The%20Web%20Layer.html#6.4.5%20Mapping%20to%20HTTP%20methods"&gt;mapping actions to request methods&lt;/a&gt; so that &lt;em&gt;GET&lt;/em&gt; and &lt;em&gt;HEAD&lt;/em&gt; requests dispatch to different actions.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-2675308762255116633?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/2675308762255116633/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=2675308762255116633' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/2675308762255116633'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/2675308762255116633'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2011/08/grails-gotcha-beware-head-requests-when.html' title='Grails Gotcha: Beware HEAD requests when rendering binary output in controllers'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-1401510321418882064</id><published>2011-08-18T21:42:00.000+01:00</published><updated>2011-08-19T10:18:47.271+01:00</updated><title type='text'>Data-driven variation with Spock</title><content type='html'>&lt;p&gt;Spock&amp;#8217;s &lt;code&gt;where:&lt;/code&gt; block is commonly used with a &lt;a href="https://github.com/robfletcher/grails-enhanced-scaffolding/blob/master/test/projects/scaffolding-example/test/functional/scaffolding/InputTypesSpec.groovy#L18"&gt;data table&lt;/a&gt; but can also be driven by any &lt;code&gt;Iterable&lt;/code&gt; data. It&amp;#8217;s worth bearing in mind that the data driving the &lt;code&gt;where:&lt;/code&gt; block doesn&amp;#8217;t have to be hardcoded, it can be dynamic. For example, today we implemented a spec to ensure that every table in our database schema has a primary key (because it&amp;#8217;s required by &lt;a href="http://ha-jdbc.sourceforge.net/"&gt;HA-JDBC&lt;/a&gt; and not automatically added by GORM on join tables). In this spec the &lt;code&gt;where:&lt;/code&gt; block is driven by the list of table names read from the database metadata.&lt;/p&gt;&lt;script src="https://gist.github.com/1154459.js?file=DatabaseSchemaSpec.groovy"&gt;&lt;/script&gt;&lt;noscript&gt;&lt;pre&gt;&lt;code&gt;import grails.plugin.spock.IntegrationSpec&lt;br /&gt;import java.sql.Connection&lt;br /&gt;import javax.sql.DataSource&lt;br /&gt;import spock.lang.*&lt;br /&gt;&lt;br /&gt;class DatabaseSchemaSpec extends IntegrationSpec {&lt;br /&gt;&lt;br /&gt;    @Shared def dataSource&lt;br /&gt;    @Shared List&lt;string&gt; tableNames&lt;br /&gt;&lt;br /&gt;    def setupSpec() {&lt;br /&gt;        DataSource.mixin(DataSourceCategory)&lt;br /&gt;&lt;br /&gt;        tableNames = []&lt;br /&gt;        dataSource.withConnection {connection -&gt;&lt;br /&gt;            def rs = connection.metaData.getTables(null, null, '%', ['TABLE'] as String[])&lt;br /&gt;            while (rs.next()) {&lt;br /&gt;                tableNames &lt;&lt; rs.getString(3)&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @Unroll("the #table table has a primary key")&lt;br /&gt;    void "all tables have a primary key"() {&lt;br /&gt;        expect:&lt;br /&gt;        dataSource.withConnection { Connection connection -&gt;&lt;br /&gt;            assert connection.metaData.getPrimaryKeys(null, null, table).next()&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        where:&lt;br /&gt;        table &lt;&lt; tableNames&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@Category(DataSource)&lt;br /&gt;class DataSourceCategory {&lt;br /&gt;    static void withConnection(dataSource, Closure closure) {&lt;br /&gt;        Connection connection = dataSource.connection&lt;br /&gt;        try {&lt;br /&gt;            closure(connection)&lt;br /&gt;        } finally {&lt;br /&gt;            connection?.close()&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;/noscript&gt;&lt;p&gt;Something like this could be done with JUnit, of course. A test could iterate over the table names and assert that each has a primary key. However, such a test would fail fast whereas with the power of Spock&amp;#8217;s &lt;code&gt;@Unroll&lt;/code&gt; annotation the spec creates a separate test result for each database table and will run each individually regardless of whether any others pass or fail. The command line output from this spec will be enough to tell you which tables do not have primary keys as &lt;code&gt;@Unroll&lt;/code&gt; puts the table name right in the test name.&lt;/p&gt;&lt;p&gt;The other great thing about this spec is that it doesn&amp;#8217;t require maintenance; as we add more domain classes to our app the spec will automatically check the associated tables.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-1401510321418882064?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/1401510321418882064/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=1401510321418882064' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/1401510321418882064'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/1401510321418882064'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2011/08/data-driven-variation-with-spock.html' title='Data-driven variation with Spock'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-4763060328082722658</id><published>2011-08-02T13:01:00.002+01:00</published><updated>2011-08-02T13:05:10.050+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='spring'/><category scheme='http://www.blogger.com/atom/ns#' term='i18n'/><title type='text'>Avoiding accidental i18n in Grails</title><content type='html'>We’re developing an app that’s exclusively for a UK audience so i18n really isn’t an issue for us. However recently we got bitten by some i18n creeping in where we didn’t want it. Specifically, when using Grails’ &lt;code&gt;g:dateFormat&lt;/code&gt; tag the default behaviour is to format the date according to the &lt;code&gt;Locale&lt;/code&gt; specified in the user’s &lt;code&gt;Accept-Language&lt;/code&gt; header. Even though we are explicitly specifying a format pattern for the date Java is aware of localized day names for some languages so the output can vary. The result is that on a page full of English text there suddenly appears a Spanish or Swedish day name. What makes things worse is that as we use server-side content caching and a CDN if a user with a non-English &lt;code&gt;Accept-Language&lt;/code&gt; header is the first to see a particular page or bit of dynamically retrieved content then the cache is primed and until it expires &lt;em&gt;everyone&lt;/em&gt; will see the non-English day name text.&lt;br /&gt;The solution in a Grails app is as simple as replacing Spring’s standard &lt;code&gt;localeResolver&lt;/code&gt; bean with an instance of &lt;code&gt;FixedLocaleResolver&lt;/code&gt;. Just add the following to &lt;em&gt;grails-app/conf/spring/resources.groovy&lt;/em&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;localResolver(org.springframework.web.servlet.i18n.FixedLocaleResolver, Locale.UK)&lt;/code&gt;&lt;/pre&gt;This changes the way Spring works out the request locale and any locale-aware tags should just fall into place.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-4763060328082722658?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/4763060328082722658/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=4763060328082722658' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/4763060328082722658'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/4763060328082722658'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2011/08/avoiding-accidental-i18n-in-grails.html' title='Avoiding accidental i18n in Grails'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-7437323314519015952</id><published>2011-05-21T21:59:00.000+01:00</published><updated>2011-05-21T21:59:06.667+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='resources'/><category scheme='http://www.blogger.com/atom/ns#' term='progressive enhancement'/><title type='text'>Resources plugin and modular web components for Grails apps</title><content type='html'>&lt;p&gt;I recently gave a talk on &lt;a href="http://www.eu2011.gr8conf.org/talk/progressive-uis"&gt;&amp;#8216;Building progressive UIs with Grails&amp;#8217;&lt;/a&gt; at &lt;a href="http://www.eu2011.gr8conf.org/"&gt;gr8conf&lt;/a&gt; in Copenhagen and was really pleased with the feedback &amp;amp; comments I received afterwards. There was a question asked at the end that I felt in retrospect I could have answered better, though. I had mentioned that the Grails &lt;a href="http://grails.org/doc/latest/guide/6.%20The%20Web%20Layer.html#6.7%20Ajax"&gt;AJAX tags&lt;/a&gt; were something that should be avoided as they write script blocks directly into the page and event handlers directly onto HTML elements. I was pitching an approach based on a clean separation of clean semantic markup and script enhancements and inline script violates that separation.&lt;/p&gt;&lt;p&gt;I was asked if there might be any kind of tags that could be developed that provided a more appropriate replacement and answered that since modern JavaScript frameworks such as &lt;a href="http://api.jquery.com/category/ajax/"&gt;jQuery&lt;/a&gt; make decorating elements with AJAX functionality so easy that I didn&amp;#8217;t think there was much point.&lt;/p&gt;&lt;p&gt;I wouldn&amp;#8217;t want anyone to understand me to mean that creating taglibs and GSP templates for modular components of your pages is a bad thing. I&amp;#8217;d just advocate keeping the script out of them. Custom tags that write out markup or delegate to templates can be really useful for building complex reusable modules. Pairing those with external JavaScript files that enhance the generated markup would be very effective.&lt;/p&gt;&lt;p&gt;If you&amp;#8217;re using the &lt;a href="http://grails.org/plugin/resources"&gt;resources plugin&lt;/a&gt; (and really… you should be) then there&amp;#8217;s a really neat way to tie the taglib or template to the JavaScript file as well. I did briefly mention this in my talk but it&amp;#8217;s worth expanding on here as it&amp;#8217;s a technique with a lot of potential.&lt;/p&gt;&lt;p&gt;The resources plugin&amp;#8217;s &lt;code&gt;r:use&lt;/code&gt; tag doesn&amp;#8217;t write out anything directly to the page but rather adds a resource module to a list that will get written out at the appropriate place in the page when the &lt;code&gt;r:layoutResources&lt;/code&gt; tag is used. This means modular components throughout the page can declare a dependency on JavaScript and CSS resources by simply calling &lt;code&gt;r:use&lt;/code&gt;. In a complex app this can be a real boon as it might not be obvious from the top level GSP exactly which modules are going to get rendered. Also if a module is later added to or removed from a page you don&amp;#8217;t need to worry about fiddling around with resource declarations in the top level GSP. Taglibs or templates become real drop in components whilst maintaining a nice clean separation of markup and script. Even better, if you use the same resource dependency multiple times the plugin ensures the resources are actually only linked once.&lt;/p&gt;&lt;p&gt;Since &lt;code&gt;r:layoutResources&lt;/code&gt; is typically used in a SiteMesh layout the resources your module depends on can even be ones that need to appear in the &lt;code&gt;head&lt;/code&gt; of the document. The SiteMesh is rendered after the GSP it decorates so any &lt;code&gt;r:use&lt;/code&gt; calls will already have been made.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-7437323314519015952?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/7437323314519015952/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=7437323314519015952' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/7437323314519015952'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/7437323314519015952'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2011/05/resources-plugin-and-modular-web.html' title='Resources plugin and modular web components for Grails apps'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-6507981728089211784</id><published>2011-03-26T16:25:00.008Z</published><updated>2011-03-26T16:39:41.622Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='css'/><title type='text'>CSS box model hacking</title><content type='html'>&lt;p&gt;Want to make an HTML element fill 100% of its parent&amp;#8217;s width but also give it a border and/or some padding? Since the width of an element is &lt;em&gt;exclusive&lt;/em&gt; of its border and padding this can be a pain. However there&amp;#8217;s a fairly simple CSS solution that works cross-browser.&lt;/p&gt;&lt;p&gt;Here&amp;#8217;s an example. Both input boxes are set to &lt;code&gt;width: 100%&lt;/code&gt; and have &lt;code&gt;padding: 5px&lt;/code&gt;. The first input shows the problem. Because the padding and border are added to the width of the element it overflows its container. The box model of the second input has been modified so that the padding and border are &lt;em&gt;inside&lt;/em&gt; the declared width.&lt;/p&gt;&lt;style&gt;    #example {        border-style: dotted;        background: #ccc;        margin: 0 auto;        padding: 5px;        width: 300px;    }    #example, #example input {        border-color: #444;        border-width: 1px;    }    #example input {        border-style: solid;    }    #example label {        cursor: pointer;        display: block;    }    #example input {        padding: 5px;        width: 100%;    }    #example #example-2 {        -moz-box-sizing: border-box;        -webkit-box-sizing: border-box;        -ms-box-sizing: border-box;        box-sizing: border-box;    }&lt;/style&gt;&lt;fieldset id="example"&gt;    &lt;label for="example-1"&gt;Field 1&lt;/label&gt;    &lt;input id="example-1"&gt;    &lt;label for="example-2"&gt;Field 2&lt;/label&gt;    &lt;input id="example-2"&gt;&lt;/fieldset&gt;&lt;p&gt;The trick to modifying the box model is to set &lt;code&gt;box-sizing: border-box&lt;/code&gt;. Unfortunately that&amp;#8217;s not a cross-browser property, only Opera supports it at the moment. To get the same effect in other browsers you will also need to set browser-specific versions as well:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;   -moz-box-sizing: border-box;&lt;br /&gt;-webkit-box-sizing: border-box;&lt;br /&gt;    -ms-box-sizing: border-box;&lt;br /&gt;        box-sizing: border-box;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Note that Internet Explorer only supports the &lt;code&gt;-ms-box-sizing&lt;/code&gt; property from version 8 upwards so you should probably be judicious with this technique or use an alternative method to get a similar effect in IE7 and below.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-6507981728089211784?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/6507981728089211784/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=6507981728089211784' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/6507981728089211784'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/6507981728089211784'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2011/03/css-box-model.html' title='CSS box model hacking'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-9172129970937219361</id><published>2011-03-25T00:10:00.001Z</published><updated>2011-03-26T17:54:06.768Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='webkit'/><category scheme='http://www.blogger.com/atom/ns#' term='firefox'/><category scheme='http://www.blogger.com/atom/ns#' term='safari'/><category scheme='http://www.blogger.com/atom/ns#' term='html5'/><category scheme='http://www.blogger.com/atom/ns#' term='chrome'/><category scheme='http://www.blogger.com/atom/ns#' term='opera'/><category scheme='http://www.blogger.com/atom/ns#' term='css'/><title type='text'>Styling with HTML5 form validation</title><content type='html'>&lt;p&gt;HTML5 specifies a number of enhancements to form inputs that are gradually being implemented by newer browsers. Among the enhancements is support for some level of automatic form validation. When inputs have invalid values the browser may refuse to submit the form. Currently Opera, Safari, Chrome and Firefox 4 have some support for this. IE8 does not. I haven&amp;#8217;t experimented with IE9 yet.&lt;/p&gt;&lt;p&gt;Let&amp;#8217;s look at &lt;a href="http://inputvalidation.s3-website-us-east-1.amazonaws.com/"&gt;an example&lt;/a&gt;. A simple registration form has inputs for the &lt;em&gt;name&lt;/em&gt;, &lt;em&gt;email&lt;/em&gt; and &lt;em&gt;website&lt;/em&gt; of a prospective user. Of these &lt;em&gt;name&lt;/em&gt; and &lt;em&gt;email&lt;/em&gt; are required. The input elements are as follows:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;input type="text" name="name" required&amp;gt;&lt;br /&gt;&amp;lt;input type="email" name="email" required&amp;gt;&lt;br /&gt;&amp;lt;input type="url" name="website"&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;required&lt;/code&gt; attribute is new in HTML5 as are the input types &lt;code&gt;email&lt;/code&gt; and &lt;code&gt;url&lt;/code&gt;. All of these have implications for validation. Additionally the new input types, whilst they appear just like regular text inputs in desktop browsers are great for mobile users as they are given optimised virtual keyboard layouts.&lt;/p&gt;&lt;p&gt;CSS3 has &lt;code&gt;:invalid&lt;/code&gt;, &lt;code&gt;:required&lt;/code&gt; and &lt;code&gt;:optional&lt;/code&gt; pseudo-classes that are supported by current versions of Firefox, Chrome, Safari and Opera. Some browsers also refuse to submit the form if a &lt;code&gt;required&lt;/code&gt; field is not filled in or invalid values are entered in &lt;code&gt;url&lt;/code&gt; or &lt;code&gt;email&lt;/code&gt; type fields. Obviously without appropriate feedback this could be a pretty disastrous user experience and thankfully even the Webkit browsers which until recently were blocking form submission without feedback are now handling things better.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;em&gt;Firefox 4&lt;/em&gt;, &lt;em&gt;Opera 11.01&lt;/em&gt; and &lt;em&gt;Chrome 10.0.648.204&lt;/em&gt; all block form submission if there is an empty &lt;code&gt;required&lt;/code&gt; field or invalid value and display a message next to the first such field.&lt;/li&gt;&lt;li&gt;&lt;em&gt;Safari 5.0.4&lt;/em&gt; will apply &lt;code&gt;:invalid&lt;/code&gt; CSS rules but allows the form to be submitted.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Applying styles to invalid fields is pretty easy. For example to highlight invalid fields with a red border and background:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;input {&lt;br /&gt;    border: 1px solid #ccc;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;input:invalid {&lt;br /&gt;    background: #fff3f3;&lt;br /&gt;    border-color: #f66;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You can also combine the &lt;code&gt;:invalid&lt;/code&gt; pseudo-class in combination with others. For example to highlight focused fields with a fancy CSS3 box-shadow:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;input:focus {&lt;br /&gt;    border-color: #99f;&lt;br /&gt;    outline: none;&lt;br /&gt;     -moz-box-shadow: 0 0 0.25em #99f; &lt;br /&gt;  -webkit-box-shadow: 0 0 0.25em #99f; &lt;br /&gt;          box-shadow: 0 0 0.25em #99f; &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;input:focus:invalid {&lt;br /&gt;     -moz-box-shadow: 0 0 0.25em #f66; &lt;br /&gt;  -webkit-box-shadow: 0 0 0.25em #f66; &lt;br /&gt;          box-shadow: 0 0 0.25em #f66;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It&amp;#8217;s worth noting that Firefox 4 automatically adds a red box-shadow to invalid fields (and not just focused ones). To turn it off you can specify:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;input:invalid {&lt;br /&gt;    -moz-box-shadow: none;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Of course, the browsers that display messages when they refuse to submit a form do so with different text and different visual effects so creating a consistent cross-browser look and feel with both client and server side validation messages is going to be an interesting challenge.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-9172129970937219361?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/9172129970937219361/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=9172129970937219361' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/9172129970937219361'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/9172129970937219361'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2011/03/styling-with-html5-form-validation.html' title='Styling with HTML5 form validation'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-8237110504061873941</id><published>2011-03-06T20:08:00.001Z</published><updated>2011-03-06T20:10:00.150Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='forms'/><category scheme='http://www.blogger.com/atom/ns#' term='html5'/><category scheme='http://www.blogger.com/atom/ns#' term='ux'/><title type='text'>Date and time inputs vs. usability</title><content type='html'>&lt;p&gt;Form input controls for date/time values have always been problematic. The more I experiment with different options, the more I think there is no one-size-fits-all solution.&lt;/p&gt;&lt;h2 id="calendar_widgets"&gt;Calendar widgets&lt;/h2&gt;&lt;p&gt;Calendar widgets such as the &lt;a href="http://jqueryui.com/demos/datepicker/"&gt;jQuery UI date picker&lt;/a&gt; or the &lt;a href="http://dev.opera.com/articles/view/new-form-features-in-html5/#input-datetime" title="&amp;lt;input type=&amp;quot;date&amp;quot;&amp;gt; and other date/time controls at Dev.Opera"&gt;Opera HTML5 date input&lt;/a&gt; are very popular and can be a slick looking addition to a form. I don&amp;#8217;t think they&amp;#8217;re entirely positive though and certainly don&amp;#8217;t work in all situations. They&amp;#8217;re great when you don&amp;#8217;t know exactly the date you want (&lt;em&gt;I want to book a flight around Easter time&lt;/em&gt;) or you need to have an overview of the calendar (&lt;em&gt;I need to set a reminder for &lt;a href="http://twitter.com/#!/LondonGGUG" title="London Groovy &amp;amp; Grails User Group on Twitter"&gt;GGUG&lt;/a&gt; on the third Tuesday of every month&lt;/em&gt;). However, when trying to enter your date of birth the widget is just in the way. Even if the widget is keyboard accessible and doesn&amp;#8217;t force you to page month-by-month to the correct year you can almost certainly type the date quicker than you can find and select it in a calendar widget.&lt;/p&gt;&lt;h2 id="multi_field_inputs"&gt;Multi-field inputs&lt;/h2&gt;&lt;p&gt;A multi-field input works well for entering familiar dates such as your date of birth or for transcribing data. They&amp;#8217;re not so good when you need the context a calendar widget affords (please don&amp;#8217;t force your users to mentally calculate what date the 3rd Tuesday of next month is).&lt;/p&gt;&lt;p&gt;With a multi-field input it&amp;#8217;s vital to remember that users in different places will expect to enter dates in a different order. For example, here in the UK we use the completely logical &lt;em&gt;dd mm yyyy&lt;/em&gt; order whilst an American will, bizarrely, want to put the month before the day. It&amp;#8217;s not particularly difficult to build a tag that renders the fields in a different order according to the request locale. Using &lt;a href="http://diveintohtml5.org/forms.html#placeholder" title="Placeholder Text at Dive Into HTML5"&gt;the HTML5 &lt;em&gt;placeholder&lt;/em&gt; attribute&lt;/a&gt; (or a suitable fallback for older browsers) is invaluable to ensure that users know which field is which.&lt;/p&gt;&lt;p&gt;A possible optimisation is to auto-tab between fields after the user has typed the requisite number of digits. In that case you should allow for the user to correct mistakes, so backspacing or using the cursor keys should also automatically jump between fields otherwise the auto-tabbing behaviour becomes more a hinderance than a help for fat-fingered typists like me.&lt;/p&gt;&lt;h2 id="selects_in_a_multi_field_input"&gt;Selects in a multi-field input&lt;/h2&gt;&lt;p&gt;It&amp;#8217;s very common to use a &lt;code&gt;select&lt;/code&gt; input for some or all portions of the date. Personally, I pretty much detest this practice as it combines all the inconvenience of a calendar widget with none of the contextual information. &lt;a href="http://grails.org/doc/latest/ref/Tags/datePicker.html" title="datePicker tag in the Grails user guide"&gt;Grails&amp;#8217; &amp;lt;g:datePicker&amp;gt; tag&lt;/a&gt; does exactly this. Not only are &lt;code&gt;select&lt;/code&gt; elements like this bulking out the page with huge option lists (Grails&amp;#8217; datePicker dumps 8.6Kb of markup in your page &lt;em&gt;without&lt;/em&gt; time fields!) but they are cumbersome to input values into with the keyboard because so many values start with the same character. An arguable exception is a &lt;code&gt;select&lt;/code&gt; for the month field as presenting textual values rather than numbers is a little friendlier and the option list is short enough and the values distinct enough to allow for reasonably quick keyboard selection.&lt;/p&gt;&lt;p&gt;I suspect the rationale for using &lt;code&gt;select&lt;/code&gt; elements is often that it all but ensures the user can&amp;#8217;t enter an invalid value (I&amp;#8217;ve even seen significant hoop-jumping done in Javascript to ensure values such as &lt;em&gt;30th February&lt;/em&gt; can&amp;#8217;t be entered). I think it&amp;#8217;s preferable to give the user a clear input and trust them to do the right thing with it rather than forcing them to use an awkward input so that they &lt;em&gt;can&amp;#8217;t&lt;/em&gt; get it wrong.&lt;/p&gt;&lt;h2 id="simple_textual_inputs"&gt;Simple textual inputs&lt;/h2&gt;&lt;p&gt;You shouldn&amp;#8217;t rule out using just a basic text input. In fact for monotonous data entry purposes it is probably optimal. The keystrokes to enter a date become muscle memory and there&amp;#8217;s no fiddling about tabbing between day, month and year fields or grabbing the mouse to pick options from a select element. Obviously the down-side is that a plain text input is error-prone and very liable to confuse users unless the expected format is made clear.&lt;/p&gt;&lt;h2 id="html5"&gt;HTML5&lt;/h2&gt;&lt;p&gt;HTML5 specifies &lt;a href="http://diveintohtml5.org/forms.html#type-date" title="Date Pickers at Dive Into HTML5"&gt;various new date and time input types&lt;/a&gt; which seems like good news but has some significant drawbacks at the moment. I can only imagine the new input types are designed to be rendered as native browser widgets (currently only Opera actually does so) as the required format is just about the most inconvenient imaginable for text entry. Sure, as a developer it&amp;#8217;s appealing to require that dates have to be entered as &lt;code&gt;yyyy-mm-dd&lt;/code&gt; as you no longer have to support varied input formats but no user in the world would naturally type a date that way. Therefore, to make such inputs usable you really need to use Javascript to proxy them with a widget or a set of multi-field inputs. Fine, but what about users who disable Javascript or use mobile or assistive devices that might not cope particularly well with the widgets? The fallback - a text input into which the user must type a &lt;a href="http://tools.ietf.org/html/rfc3339#section-5.8" title="Examples of RFC3339 date values"&gt;machine-readable RFC3339 date&lt;/a&gt; - is pretty unfriendly.&lt;/p&gt;&lt;p&gt;What&amp;#8217;s worse is that Webkit based browsers such as Chrome and Safari will render the new input types as regular text inputs but refuse to submit a form containing incorrectly formatted values and unbelievably provide no user feedback whatsoever when they do so.&lt;/p&gt;&lt;p&gt;I&amp;#8217;m inclined to think that the useful support for the new input types is so minimal and the actively user-hostile handling of them so much more widespread that they&amp;#8217;re best avoided altogether.&lt;/p&gt;&lt;p&gt;So, to sum up:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Think about who your users are and what they are trying to accomplish with &lt;em&gt;this particular&lt;/em&gt; input field and give them the right input for the job at hand.&lt;/li&gt;&lt;li&gt;If they need to type some or all of the value make sure it&amp;#8217;s clear what format is expected or which field is which.&lt;/li&gt;&lt;li&gt;Allow for people to enter values in the order they are comfortable with and above all &lt;em&gt;don&amp;#8217;t&lt;/em&gt; force them to type it in a machine-readable format.&lt;/li&gt;&lt;li&gt;Don&amp;#8217;t strand Chrome and Safari users with broken HTML5 input types.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-8237110504061873941?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/8237110504061873941/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=8237110504061873941' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/8237110504061873941'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/8237110504061873941'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2011/03/form-input-controls-for-datetime-values.html' title='Date and time inputs vs. usability'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-8597427797360162967</id><published>2011-02-22T22:31:00.000Z</published><updated>2011-02-22T22:31:06.869Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='webkit'/><category scheme='http://www.blogger.com/atom/ns#' term='safari'/><category scheme='http://www.blogger.com/atom/ns#' term='html5'/><category scheme='http://www.blogger.com/atom/ns#' term='chrome'/><title type='text'>JavaScript's history object, pushState and the back button</title><content type='html'>&lt;p&gt;I&amp;#8217;m not sure if it&amp;#8217;s the immaturity of the browser support or my general uselessness but I&amp;#8217;ve been having some trouble with the JavaScript &lt;em&gt;history&lt;/em&gt; API.&lt;/p&gt;&lt;p&gt;I won&amp;#8217;t try to explain the &lt;em&gt;history&lt;/em&gt; API here, it&amp;#8217;s pretty well covered at &lt;a href="https://developer.mozilla.org/en/DOM/Manipulating_the_browser_history" title="&amp;quot;Manipulating the browser history&amp;quot; at Mozilla Developer Network"&gt;Mozilla Developer Network&lt;/a&gt; and &lt;a href="http://dev.w3.org/html5/spec-author-view/history.html" title="&amp;quot;Session history and navigation&amp;quot; at HTML5 Edition for Web Authors"&gt;W3&lt;/a&gt;. The basics are simple enough:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The API provides two methods; &lt;a href="http://dev.w3.org/html5/spec/history.html#dom-history-pushstate"&gt;&lt;code&gt;pushState&lt;/code&gt;&lt;/a&gt; which allows you to add a new entry to the browser history and &lt;a href="http://dev.w3.org/html5/spec/history.html#dom-history-replacestate"&gt;&lt;code&gt;replaceState&lt;/code&gt;&lt;/a&gt; which modifies the current history entry.&lt;/li&gt;&lt;li&gt;New entries added to history using &lt;code&gt;pushState&lt;/code&gt; can be navigated via the browser&amp;#8217;s &lt;em&gt;back&lt;/em&gt; and &lt;em&gt;forward&lt;/em&gt; buttons and a &lt;code&gt;popstate&lt;/code&gt; event is fired on the &lt;code&gt;window&lt;/code&gt; object when this happens.&lt;/li&gt;&lt;li&gt;Both methods allow you to attach arbitrary data to the history entry that you can use to reconstruct the appropriate page state when the user uses the &lt;em&gt;back&lt;/em&gt; or &lt;em&gt;forward&lt;/em&gt; buttons.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;I imagine a pretty typical use-case is what I&amp;#8217;ve been trying to do with the pagination and sorting on the list pages of &lt;em&gt;Grails&lt;/em&gt; scaffolding. Instead of pagination links and column headers causing a full page reload when clicked I intercept the click event and send an AJAX request getting back a page fragment I can use to update the list in the page. Easy enough, however without the &lt;em&gt;history&lt;/em&gt; API it will break the back and forward buttons and make deep linking impossible. This isn&amp;#8217;t an acceptable option so in true &lt;a href="http://en.wikipedia.org/wiki/Progressive_enhancement" title="&amp;quot;Progressive enhancement&amp;quot; at Wikipedia"&gt;progressive enhancement&lt;/a&gt; style I&amp;#8217;ve used &lt;a href="http://www.modernizr.com/" title="Modernizr JavaScript library"&gt;Modernizr&lt;/a&gt; and only apply the AJAX behaviour if the browser supports the &lt;em&gt;history&lt;/em&gt; API.&lt;/p&gt;&lt;p&gt;The essence of the script involved is this:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;var links =     //... pagination and sorting links&lt;br /&gt;var container = //... the region of the page that will be updated with AJAX&lt;br /&gt;&lt;br /&gt;// override clicks on the links&lt;br /&gt;links.live('click', function() {&lt;br /&gt;    // grab the link's URL&lt;br /&gt;    var url = $(this).attr('href');&lt;br /&gt;    // add a new history entry&lt;br /&gt;    history.pushState({ path: url }, '', url);&lt;br /&gt;    // load the page fragment into the container with AJAX&lt;br /&gt;    container.load(url);&lt;br /&gt;    // prevent the link click bubbling&lt;br /&gt;    return false;&lt;br /&gt;});&lt;br /&gt;&lt;br /&gt;// handle the back and forward buttons&lt;br /&gt;$(window).bind('popstate', function(event) {&lt;br /&gt;    // if the event has our history data on it, load the page fragment with AJAX&lt;br /&gt;    var state = event.originalEvent.state;&lt;br /&gt;    if (state) {&lt;br /&gt;        container.load(state.path);&lt;br /&gt;    }&lt;br /&gt;});&lt;br /&gt;&lt;br /&gt;// when the page first loads update the history entry with the URL&lt;br /&gt;// needed to recreate the 'first' page with AJAX&lt;br /&gt;history.replaceState({ path: window.location.href }, '');&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;At first glance this works pretty nicely. In browsers that support &lt;em&gt;history&lt;/em&gt; (right now that&amp;#8217;s just Chrome, Safari and its mobile variants) paginating and sorting the list does not refresh the entire page but the browser&amp;#8217;s location bar &lt;em&gt;is&lt;/em&gt; updated so copy-pasting or bookmarking the URL will give a valid link to the current page. What&amp;#8217;s more, the back and forward buttons can be used to step back through the list pages just as if we reloaded the whole page. In non-&lt;em&gt;history&lt;/em&gt;-compliant browsers the list page behaves just like it always did; the links reload the entire page.&lt;/p&gt;&lt;p&gt;Unfortunately there&amp;#8217;s a problem that was &lt;a href="https://github.com/robfletcher/grails-scaffolding/issues#issue/2"&gt;reported to me on GitHub&lt;/a&gt; shortly after I uploaded a demo of my scaffolding work. Where everything falls down is when you paginate the list, follow a link off the page (or just use a bookmark or type in a URL), then use the &lt;em&gt;back&lt;/em&gt; button to return to it. In Chrome and iPad/iPhone variants of Safari the browser displays just the page fragment from the last AJAX call, losing all the surrounding page along with styling, scripts, etc.&lt;/p&gt;&lt;p&gt;Where things get very odd is that adding a &lt;code&gt;Cache-Control: no-cache&lt;/code&gt; header to the AJAX responses makes the problem disappear, presumably because the browser then doesn&amp;#8217;t cache the AJAX response and has to use the historical URL to reload the entire page. Remember, in good progressive enhancement style the URL for the full page or the fragment is the same. The server uses the &lt;code&gt;X-Requested-With&lt;/code&gt; header to decide whether to return a fragment or the whole page. Obviously, forgoing caching is hardly an acceptable compromise but it&amp;#8217;s interesting in that it reveals what the browser is doing. It can&amp;#8217;t, surely, be right for the browser to treat a page fragment the same as a full document!&lt;/p&gt;&lt;p&gt;Curiously in &lt;em&gt;desktop&lt;/em&gt; Safari this doesn&amp;#8217;t happen and the full page is loaded as you would hope. Looking at the &lt;em&gt;User-Agent&lt;/em&gt; header it looks like Safari is using an older version of WebKit (&lt;em&gt;533.19.4&lt;/em&gt; rather than &lt;em&gt;534.13&lt;/em&gt;).&lt;/p&gt;&lt;p&gt;You can see the behaviour in my &lt;a href="http://scaffolding.elasticbeanstalk.com/" title="Grails Scaffolding sample app"&gt;scaffolding sample app&lt;/a&gt;. I also ran into the exact same issue today at work whilst trying to add history navigation to &lt;a href="http://skyliving.sky.com/celebrity/find-a-celebrity" title="Celebrity Finder on Sky Living"&gt;this page&lt;/a&gt; (which is a good example of why you&amp;#8217;d want to use &lt;em&gt;history&lt;/em&gt; in the first place). I don&amp;#8217;t think it&amp;#8217;s just me, either. The same problem can be seen with the demo linked from &lt;a href="http://js-html5.com/post/3014620142/history-api" title="&amp;quot;Using the History API&amp;quot; at JavaScript in HTML5"&gt;this post&lt;/a&gt; about the &lt;em&gt;history&lt;/em&gt; API.&lt;/p&gt;&lt;p&gt;If there are any JavaScript experts out there who can point out my obvious incompetence here, that would be great. Otherwise I guess I&amp;#8217;ll have to wait for updates to WebKit to hopefully fix the issue before I can start applying this technique with confidence.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-8597427797360162967?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/8597427797360162967/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=8597427797360162967' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/8597427797360162967'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/8597427797360162967'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2011/02/javascripts-history-object-pushstate.html' title='JavaScript&apos;s history object, pushState and the back button'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-8453480822912377301</id><published>2011-02-06T15:02:00.002Z</published><updated>2011-02-06T15:08:36.307Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='intellij'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='geb'/><title type='text'>Running Geb tests from your IDE</title><content type='html'>&lt;p&gt;A frequent complaint about functional testing in Grails is that the start up / shut down cycle time of the app makes prototyping a functional test prohibitive. There has been some recent progress in this are with Luke Daley's &lt;a href="http://www.grails.org/plugin/functional-test-development"&gt;Functional test development plugin&lt;/a&gt; but it would be really nice to be able to just run functional tests from inside your IDE in the same way as a similar unit test.&lt;/p&gt;&lt;p&gt;With Geb and IntelliJ Idea at least this is actually pretty straightforward (I'm sure the same thing is possible with Eclipse/STS I'm just not familiar enough with it).&lt;/p&gt;&lt;p&gt;Geb's dependence on the Grails lifecycle is pretty minimal so the tests can run without needing any magic to happen in any &lt;em&gt;_Events&lt;/em&gt; scripts (unlike the Selenium RC plugin where this would be significantly more difficult). One extra step &lt;em&gt;is&lt;/em&gt; required; the Grails Geb plugin normally picks up its base URL from Grails configuration and the test will not be running in the same JVM as the Grails app if it runs from the IDE so configuration will not be available. Just add the following method to your test that extends &lt;em&gt;GebTests&lt;/em&gt; or &lt;em&gt;GebSpec&lt;/em&gt; (or add it to a base class):&lt;pre&gt;&lt;code&gt;@Override String getBaseUrl() {&lt;br /&gt;    super.baseUrl ?: "http://localhost:8080"&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;Now Geb will use the Grails configured base URL if it &lt;em&gt;is&lt;/em&gt; in the same JVM as the app or default to &lt;code&gt;http://localhost:8080&lt;/code&gt; otherwise (obviously you need to change that default if that's not the host or port where your app runs).&lt;/p&gt;&lt;p&gt;You can then just run up the app from the command line, open the test in IntelliJ and hit &lt;kbd&gt;Ctrl + Shift + F10&lt;/kbd&gt; to run it. When the test completes the app is still running so you can make changes &amp; run again with minimal turnaround time. Since the app is running in development mode you can make application changes without a server restart as well.&lt;/p&gt;&lt;p&gt;IntelliJ Idea's test integration is pretty good and it even groks Spock specifications. You can also debug and step through the test. The only downside is that you can't directly access domain classes or other application components in the test as they are only available from the app's JVM.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-8453480822912377301?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/8453480822912377301/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=8453480822912377301' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/8453480822912377301'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/8453480822912377301'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2011/02/running-geb-tests-from-your-ide.html' title='Running Geb tests from your IDE'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-2970867950234994907</id><published>2010-11-30T13:47:00.001Z</published><updated>2010-11-30T14:04:27.665Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='geb'/><title type='text'>Encapsulating page state and actions in Geb</title><content type='html'>&lt;p&gt;Geb &lt;em&gt;Page&lt;/em&gt; and &lt;em&gt;Module&lt;/em&gt; classes are just regular Groovy classes. In addition to the &lt;em&gt;content&lt;/em&gt; DSL you can declare methods just as you would in any other class. Those methods can use content properties directly. This is really useful for encapsulating state and actions in a reusable way.&lt;/p&gt;&lt;p&gt;In this post I want to run through a couple of simple examples of re-usable &lt;em&gt;Module&lt;/em&gt; classes that are enhanced with methods. Although the examples deal with &lt;em&gt;Module&lt;/em&gt; classes everything here is equally applicable to &lt;em&gt;Page&lt;/em&gt; classes.&lt;/p&gt;&lt;p&gt;Page object methods tend to fall into two categories:&lt;/p&gt;&lt;dt&gt;Observers&lt;/dt&gt;&lt;dd&gt;report on some aspect of page state (e.g. whether a user is logged in or not).&lt;/dd&gt;&lt;dd&gt;have non-&lt;em&gt;void&lt;/em&gt; return types (I prefer explicit return types on methods but &lt;code&gt;def&lt;/code&gt; would work too).&lt;/dd&gt;&lt;dd&gt;can be used for making assertions.&lt;/dd&gt;&lt;dt&gt;Actions&lt;/dt&gt;&lt;dd&gt;perform an action such as clicking a link or button.&lt;/dd&gt;&lt;dd&gt;will typically be &lt;em&gt;void&lt;/em&gt; (note that it's not necessary to return a &lt;em&gt;Page&lt;/em&gt; instance or class from a navigation method in &lt;em&gt;Geb&lt;/em&gt;).&lt;/dd&gt;&lt;dd&gt;throw &lt;em&gt;IllegalStateException&lt;/em&gt; if the action is invalid in the current page state.&lt;/dd&gt;&lt;p&gt;First let's consider an authentication module that can be used across every page in a site. The markup of the module can be completely different depending on whether a user is logged in or not. When not logged in a username/password form is shown:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;aside id="auth"&amp;gt; &lt;br /&gt;    &amp;lt;fieldset&amp;gt; &lt;br /&gt;        &amp;lt;legend&amp;gt;Log In&amp;lt;/legend&amp;gt; &lt;br /&gt;        &amp;lt;form action="/auth/login" method="post" &amp;gt; &lt;br /&gt;            &amp;lt;label&amp;gt;Username: &amp;lt;input name="username"/&amp;gt;&amp;lt;/label&amp;gt; &lt;br /&gt;            &amp;lt;label&amp;gt;Password: &amp;lt;input type="password" name="password"&amp;gt;&amp;lt;/label&amp;gt; &lt;br /&gt;            &amp;lt;button name="login" type="submit"&amp;gt;Log In&amp;lt;/button&amp;gt; &lt;br /&gt;        &amp;lt;/form&amp;gt; &lt;br /&gt;    &amp;lt;/fieldset&amp;gt; &lt;br /&gt;&amp;lt;/aside&amp;gt; &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;When logged in, a welcome message is shown:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;aside id="auth"&amp;gt; &lt;br /&gt;    Welcome back &amp;lt;span class="username"&amp;gt;blackbeard&amp;lt;/span&amp;gt; &lt;br /&gt;    &amp;lt;a href="/auth/logout" name="logout"&amp;gt;Log Out&amp;lt;/a&amp;gt; &lt;br /&gt;&amp;lt;/aside&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To model this I'll create a Geb &lt;em&gt;Module&lt;/em&gt; like this:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;class AuthModule extends Module {&lt;br /&gt;    static base = { $("aside#auth") }&lt;br /&gt;&lt;br /&gt;    static content = {&lt;br /&gt;        username(required: false) { $(".username").text() }&lt;br /&gt;        logoutButton(required: false, to: HomePage) { $("a[name=logout]") }&lt;br /&gt;        form(required: false) { $("form") }&lt;br /&gt;        loginButton(required: false, to: HomePage) { $("button[name=login]") }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;required: false&lt;/code&gt; declaration is used to declare content properties that may or may not be on the page. The &lt;code&gt;username&lt;/code&gt; and &lt;code&gt;logoutButton&lt;/code&gt; properties are only present in the logged-in state and the &lt;code&gt;form&lt;/code&gt; and &lt;code&gt;loginButton&lt;/code&gt; properties are only present in the logged-out state.&lt;/p&gt;&lt;p&gt;I can use the module in some tests like this:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;def "user can log in"() {&lt;br /&gt;    when:&lt;br /&gt;    authModule.form.username = "blackbeard"&lt;br /&gt;    authModule.form.password = "yohoho!"&lt;br /&gt;    authModule.loginButton.click()&lt;br /&gt;&lt;br /&gt;    then:&lt;br /&gt;    at HomePage&lt;br /&gt;    authModule.username == "blackbeard"&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;def "user can log out"() {&lt;br /&gt;    when:&lt;br /&gt;    authModule.logoutButton.click()&lt;br /&gt;&lt;br /&gt;    then:&lt;br /&gt;    at HomePage&lt;br /&gt;    authModule.username == null&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is a good start but there are several assumptions and bits of page detail creeping into the test. The test is using the presence or absence of the &lt;em&gt;username&lt;/em&gt; to determine if someone is logged in or not. That doesn't lead to a very meaningful assertion in the test and is assuming things about the page detail. Likewise the login step is quite long-winded and likely to be repeated in a lot of tests. Not only that but it won't work if a user is already logged in as the form fields won't be present on the page.&lt;/p&gt;&lt;p&gt;To encapsulate the module's state and actions better I'll add the following methods:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;boolean isLoggedIn() { username }&lt;br /&gt;&lt;br /&gt;void login(String username, String password = "password") {&lt;br /&gt;    if (loggedIn) throw new IllegalStateException("already logged in")&lt;br /&gt;    form.username = username&lt;br /&gt;    form.password = password&lt;br /&gt;    loginButton.click()&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void logout() {&lt;br /&gt;    if (!loggedIn) throw new IllegalStateException("already logged out")&lt;br /&gt;    logoutButton.click()&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The methods declared by the module abstract some detail away very effectively. The &lt;code&gt;isLoggedIn&lt;/code&gt; method means I can change the login detection mechanism later and just change the module's method rather than a bunch of tests. The &lt;code&gt;login&lt;/code&gt; and &lt;code&gt;logout&lt;/code&gt; methods abstract away the &lt;em&gt;how&lt;/em&gt; of logging in and out so the test can just deal with the &lt;em&gt;what&lt;/em&gt;. I've used &lt;em&gt;IllegalStateException&lt;/em&gt; for cases where a method is called when the module is not in the correct state. The tests now look much clearer:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;def "user can log in"() {&lt;br /&gt;    when:&lt;br /&gt;    authModule.login "blackbeard"&lt;br /&gt;&lt;br /&gt;    then:&lt;br /&gt;    at HomePage&lt;br /&gt;    authModule.username == "blackbeard"&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;def "user can log out"() {&lt;br /&gt;    when:&lt;br /&gt;    authModule.logout()&lt;br /&gt;&lt;br /&gt;    then:&lt;br /&gt;    at HomePage&lt;br /&gt;    !authModule.loggedIn&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Another good example of encapsulating state and behaviour like this is a typical pagination module that would appear on a list or search results page. The markup would look something like this (I've omitted the link &lt;code&gt;href&lt;/code&gt; attributes for clarity):&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;nav class="pagination"&amp;gt;&lt;br /&gt;    &amp;lt;a class="prevLink"&amp;gt;Previous&amp;lt;/a&amp;gt;&lt;br /&gt;    &amp;lt;a class="step"&amp;gt;1&amp;lt;/a&amp;gt;&lt;br /&gt;    &amp;lt;span class="currentStep"&amp;gt;2&amp;lt;/span&amp;gt;&lt;br /&gt;    &amp;lt;a class="step"&amp;gt;3&amp;lt;/a&amp;gt;&lt;br /&gt;    &amp;lt;a class="nextLink"&amp;gt;Next&amp;lt;/a&amp;gt;&lt;br /&gt;&amp;lt;/nav&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;em&gt;previous&lt;/em&gt; and &lt;em&gt;next&lt;/em&gt; links will only appear when there is a previous or next page and no links will be present at all if there is only a single page. The following &lt;em&gt;Module&lt;/em&gt; class models the state and actions of this component:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;class Pagination extends Module {&lt;br /&gt;    static content = {&lt;br /&gt;        links(required: false) { $("a") }&lt;br /&gt;        currentPage(required: false) { $(".currentStep")?.text()?.toInteger() ?: 1 }&lt;br /&gt;        nextLink(required: false) { links.filter(".nextLink") }&lt;br /&gt;        previousLink(required: false) { links.filter(".prevLink") }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    boolean isFirstPage() {&lt;br /&gt;        previousLink.empty&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    boolean isLastPage() {&lt;br /&gt;        nextLink.empty&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    void toPage(int pageNumber) {&lt;br /&gt;        def link = links.filter(text: "$pageNumber")&lt;br /&gt;        if (!link) throw new IllegalArgumentException("Page number $pageNumber not present in pagination")&lt;br /&gt;        link.click()&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    void nextPage() {&lt;br /&gt;        if (lastPage) throw new IllegalStateException("Already on the last page")&lt;br /&gt;        nextLink.click()&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    void previousPage() {&lt;br /&gt;        if (firstPage) throw new IllegalStateException("Already on the first page")&lt;br /&gt;        previousLink.click()&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Breaking the &lt;em&gt;Module&lt;/em&gt; down in detail:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The &lt;code&gt;currentPage&lt;/code&gt; property returns the current page number as an &lt;code&gt;int&lt;/code&gt; and defaults to &lt;code&gt;1&lt;/code&gt; if there is no pagination present in the page.&lt;/li&gt;&lt;li&gt;The &lt;code&gt;isFirstPage&lt;/code&gt; and &lt;code&gt;isLastPage&lt;/code&gt; observer methods use the absence of the previous and next links respectively to determine if the current page is the first or last one.&lt;/li&gt;&lt;li&gt;The &lt;code&gt;toPage&lt;/code&gt; method finds a numbered link and clicks it, throwing &lt;em&gt;IllegalArgumentException&lt;/em&gt; if no such link is present.&lt;/li&gt;&lt;li&gt;The &lt;code&gt;nextPage&lt;/code&gt; and &lt;code&gt;previousPage&lt;/code&gt; action methods throw &lt;em&gt;IllegalStateException&lt;/em&gt; if the relevant link is not on the page.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The &lt;em&gt;Pagination&lt;/em&gt; class now neatly encapsulates the detail of the pagination elements and presents a higher-level fa&amp;ccedil;ade to the tests.&lt;/p&gt;&lt;p&gt;Fuller versions of the examples in this post can be found &lt;a href="https://github.com/robfletcher/geb-examples" title="geb-examples project on GitHub"&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-2970867950234994907?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/2970867950234994907/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=2970867950234994907' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/2970867950234994907'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/2970867950234994907'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2010/11/encapsulating-page-state-and-actions-in.html' title='Encapsulating page state and actions in Geb'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-3820750465145003723</id><published>2010-11-26T00:17:00.001Z</published><updated>2010-11-26T00:18:43.811Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='geb'/><title type='text'>Modelling repeating structures with Geb page objects</title><content type='html'>&lt;p&gt;&lt;a href="http://geb.codehaus.org/" title="Geb"&gt;Geb&lt;/a&gt; is the hot new thing in Grails functional testing. One of its most powerful features is the concise DSL for defining page objects. The reasons for using page objects are &lt;a href="http://code.google.com/p/selenium/wiki/PageObjects" title="Page Objects"&gt;well&lt;/a&gt; &lt;a href="http://robfletcher.github.com/grails-selenium-rc/docs/manual/guide/4.%20Using%20Page%20Objects.html" title="Using Page Objects"&gt;enumerated&lt;/a&gt; &lt;a href="http://geb.codehaus.org/manual/latest/pages.html#the_page_object_pattern_why" title="The Page Object Pattern - why?"&gt;elsewhere&lt;/a&gt; but the basic point is to allow your tests to interact with pages in a manner agnostic of the detail of their structure. This is both practical (you can change markup structure without having to fix numerous tests that only fail because they were tightly coupled to that structure) and aesthetic (your tests read more like a user&amp;#8217;s interaction with the page - the &lt;em&gt;what&lt;/em&gt; rather than the &lt;em&gt;how&lt;/em&gt;).&lt;/p&gt;&lt;p&gt;I want to put together a few short blog posts dealing with patterns that I find useful for defining page objects and modules in Geb. As I go I&amp;#8217;ll keep adding to a very simple Grails project showing working examples which is &lt;a href="https://github.com/robfletcher/geb-examples/"&gt;available on GitHub&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;In this post I want to talk about repeating data structures such as lists and tables and how to model them effectively.&lt;/p&gt;&lt;p&gt;A &lt;em&gt;content&lt;/em&gt; property in a Geb &lt;code&gt;Page&lt;/code&gt; or &lt;code&gt;Module&lt;/code&gt; can be any type; whatever is returned from the defining closure. This will frequently be a Geb &lt;code&gt;Navigator&lt;/code&gt; instance or a &lt;code&gt;String&lt;/code&gt; but can be whatever is useful for the tests you&amp;#8217;re writing. A good rule of thumb is that the test should be dealing with as simplified a view of the data as possible. All the complexity of traversing HTML elements and manipulating them into a useful form should be hidden away in the page objects and modules. When handling repeating data structures such as &lt;code&gt;ol&lt;/code&gt; or &lt;code&gt;table&lt;/code&gt; elements you probably want to be able to treat the content as a &lt;code&gt;List&lt;/code&gt; so that tests can use Groovy features such as iterator methods, indexing and slicing to make very expressive assertions.&lt;/p&gt;&lt;h3 id="simple_repeating_structures"&gt;Simple repeating structures&lt;/h3&gt;&lt;p&gt;For example, imagine we want to verify an &lt;code&gt;ol&lt;/code&gt; element like this:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;ol id="recent-books"&amp;gt;&lt;br /&gt;    &amp;lt;li&amp;gt;Zero History&amp;lt;/li&amp;gt;&lt;br /&gt;    &amp;lt;li&amp;gt;Surface Detail&amp;lt;/li&amp;gt;&lt;br /&gt;    &amp;lt;li&amp;gt;The Machine of Death&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The most useful type would probably be a &lt;code&gt;List&amp;lt;String&amp;gt;&lt;/code&gt; which we can get easily enough by defining our content like this:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;static content = {&lt;br /&gt;    recentBooks { $("ol#recent-books li")*.text() }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is then very easy to use in a test:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;expect:&lt;br /&gt;recentBooks == ["Zero History", "Surface Detail", "The Machine of Death"]&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="complex_repeating_structures_using_modules"&gt;Complex repeating structures using Modules&lt;/h3&gt;&lt;p&gt;A more complex example of a repeating structure is a table, where each row contains several fields. Here we can use a Geb &lt;code&gt;Module&lt;/code&gt; to represent each row, with content properties to get data from each cell. Let&amp;#8217;s say we want to verify the contents of the following table of search results:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;table id="book-results"&amp;gt;&lt;br /&gt;    &amp;lt;thead&amp;gt;&lt;br /&gt;        &amp;lt;tr&amp;gt;&lt;br /&gt;            &amp;lt;th&amp;gt;Title&amp;lt;/th&amp;gt;&lt;br /&gt;            &amp;lt;th&amp;gt;Author&amp;lt;/th&amp;gt;&lt;br /&gt;            &amp;lt;th&amp;gt;Format&amp;lt;/th&amp;gt;&lt;br /&gt;            &amp;lt;th&amp;gt;Price&amp;lt;/th&amp;gt;&lt;br /&gt;            &amp;lt;th&amp;gt;Release Date&amp;lt;/th&amp;gt;&lt;br /&gt;        &amp;lt;/tr&amp;gt;&lt;br /&gt;    &amp;lt;/thead&amp;gt;&lt;br /&gt;    &amp;lt;tbody&amp;gt;&lt;br /&gt;        &amp;lt;tr&amp;gt;&lt;br /&gt;            &amp;lt;td&amp;gt;Zero History&amp;lt;/td&amp;gt;&lt;br /&gt;            &amp;lt;td&amp;gt;William Gibson&amp;lt;/td&amp;gt;&lt;br /&gt;            &amp;lt;td&amp;gt;Hardback&amp;lt;/td&amp;gt;&lt;br /&gt;            &amp;lt;td&amp;gt;£12.29&amp;lt;/td&amp;gt;&lt;br /&gt;            &amp;lt;td&amp;gt;2 Sep 2010&amp;lt;/td&amp;gt;&lt;br /&gt;        &amp;lt;/tr&amp;gt;&lt;br /&gt;        &amp;lt;tr&amp;gt;&lt;br /&gt;            &amp;lt;td&amp;gt;Zero History&amp;lt;/td&amp;gt;&lt;br /&gt;            &amp;lt;td&amp;gt;William Gibson&amp;lt;/td&amp;gt;&lt;br /&gt;            &amp;lt;td&amp;gt;Kindle&amp;lt;/td&amp;gt;&lt;br /&gt;            &amp;lt;td&amp;gt;£11.99&amp;lt;/td&amp;gt;&lt;br /&gt;            &amp;lt;td&amp;gt;2 Sep 2010&amp;lt;/td&amp;gt;&lt;br /&gt;        &amp;lt;/tr&amp;gt;&lt;br /&gt;        &amp;lt;tr&amp;gt;&lt;br /&gt;            &amp;lt;td&amp;gt;Spook Country&amp;lt;/td&amp;gt;&lt;br /&gt;            &amp;lt;td&amp;gt;William Gibson&amp;lt;/td&amp;gt;&lt;br /&gt;            &amp;lt;td&amp;gt;Paperback&amp;lt;/td&amp;gt;&lt;br /&gt;            &amp;lt;td&amp;gt;£5.00&amp;lt;/td&amp;gt;&lt;br /&gt;            &amp;lt;td&amp;gt;31 Jul 2008&amp;lt;/td&amp;gt;&lt;br /&gt;        &amp;lt;/tr&amp;gt;&lt;br /&gt;        &amp;lt;tr&amp;gt;&lt;br /&gt;            &amp;lt;td&amp;gt;Pattern Recognition&amp;lt;/td&amp;gt;&lt;br /&gt;            &amp;lt;td&amp;gt;William Gibson&amp;lt;/td&amp;gt;&lt;br /&gt;            &amp;lt;td&amp;gt;Paperback&amp;lt;/td&amp;gt;&lt;br /&gt;            &amp;lt;td&amp;gt;£4.99&amp;lt;/td&amp;gt;&lt;br /&gt;            &amp;lt;td&amp;gt;24 Jun 2004&amp;lt;/td&amp;gt;&lt;br /&gt;        &amp;lt;/tr&amp;gt;&lt;br /&gt;    &amp;lt;/tbody&amp;gt;&lt;br /&gt;&amp;lt;/table&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We can define our module like this:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;static content = {&lt;br /&gt;    bookResults { i -&amp;gt; module BookRow, $("table#book-results tbody tr", i) }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class BookRow extends Module {&lt;br /&gt;    static content = {&lt;br /&gt;        cell { i -&amp;gt; $("td", i) }&lt;br /&gt;        title { cell(0).text() }&lt;br /&gt;        author { cell(1).text() }&lt;br /&gt;        format { cell(2).text() }&lt;br /&gt;        price { cell(3).text()[1..-1].toDouble() }&lt;br /&gt;        releaseDate { cell(4).text() }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;bookResults&lt;/code&gt; content closure takes a row number parameter and uses it to select the corresponding &lt;code&gt;tr&lt;/code&gt; from the body of the table and use that to construct a module. The module itself defines content properties with meaningful names that map to the text in each cell.&lt;/p&gt;&lt;p&gt;This isn&amp;#8217;t bad as far as it goes. We can use the module pretty effectively in tests like this:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;expect:&lt;br /&gt;bookResults(0).title == "Zero History"&lt;br /&gt;bookResults(3).price == 4.99&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;However, &lt;code&gt;bookResults&lt;/code&gt; isn&amp;#8217;t a &lt;code&gt;List&lt;/code&gt;. We can&amp;#8217;t easily get all the book titles at once or make an assertion that all the authors are the same or find the lowest price. Even querying how many rows there are would require an additional content property or method to retrieve &lt;code&gt;$("tbody tr").size()&lt;/code&gt;. The table is a repeating data structure and it would be nice to treat it as one!&lt;/p&gt;&lt;p&gt;This ought to be possible bearing in mind 3 things:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;The type of a content property is simply whatever you return from the defining closure, there&amp;#8217;s no reason we can&amp;#8217;t return a &lt;code&gt;List&amp;lt;BookRow&amp;gt;&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;There&amp;#8217;s nothing special about the expression that constructs the module itself: &lt;code&gt;module BookRow, $("tbody tr", i)&lt;/code&gt; is just a call to a method called &lt;code&gt;module&lt;/code&gt; passing a &lt;code&gt;Class&amp;lt;? extends Module&amp;gt;&lt;/code&gt; which is the module type we want and a &lt;code&gt;Navigator&lt;/code&gt; pointing to the module&amp;#8217;s root element.&lt;/li&gt;&lt;li&gt;The Geb &lt;code&gt;Navigator&lt;/code&gt; class returned by the &lt;code&gt;$&lt;/code&gt; expression implements &lt;code&gt;Iterable&amp;lt;Navigator&amp;gt;&lt;/code&gt; and can be treated like a &lt;code&gt;List&lt;/code&gt; of all the selected HTML elements.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;In fact we can get a &lt;code&gt;List&amp;lt;BookRow&amp;gt;&lt;/code&gt; easily enough if we redefine the &lt;code&gt;bookResults&lt;/code&gt; property like this:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;static content = {&lt;br /&gt;    bookResults {&lt;br /&gt;        $("tbody tr").collect {&lt;br /&gt;            module BookRow, it&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The key here is that we iterate over the &lt;code&gt;tr&lt;/code&gt; elements inside the content definition collecting a new &lt;code&gt;BookRow&lt;/code&gt; instance for each one. Now the page object doesn&amp;#8217;t require the test to pass in the index of the row it&amp;#8217;s interested in. This enables our test to do some much more powerful and interesting things:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;expect:&lt;br /&gt;bookResults.size() == 4&lt;br /&gt;bookResults[0].title == "Zero History"&lt;br /&gt;bookResults.title.unique() == ["Zero History", "Spook Country", "Pattern Recognition"]&lt;br /&gt;bookResults.every { it.author == "William Gibson" }&lt;br /&gt;bookResults[2..3].every { it.format == "Paperback" }&lt;br /&gt;bookResults.price.sum() == 34.27&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I&amp;#8217;ve tried to show a couple of reasonably simple examples here. Others are easy to imagine; a &lt;code&gt;Map&lt;/code&gt; representing the &lt;code&gt;dt&lt;/code&gt; and &lt;code&gt;dd&lt;/code&gt; elements inside an HTML definition list, a list of modules representing a group of labelled radio buttons or news items with images and links, a tree-like multi-level navigation structure, etc.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-3820750465145003723?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/3820750465145003723/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=3820750465145003723' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/3820750465145003723'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/3820750465145003723'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2010/11/modelling-repeating-structures-with-geb.html' title='Modelling repeating structures with Geb page objects'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-6986033872730769314</id><published>2010-09-24T13:48:00.001+01:00</published><updated>2010-09-27T09:40:23.672+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='i18n'/><title type='text'>Stubbing access to the g:message tag in unit tests</title><content type='html'>Grails controllers and tag libs can access any tag as though it were a method. The most common use for this is probably accessing i18n messages via the &lt;code&gt;&lt;a href="http://grails.org/doc/latest/ref/Tags/message.html"&gt;g:message&lt;/a&gt;&lt;/code&gt; tag. However, because tag access is magic wired up by Grails it's not available in unit tests without some effort.&lt;br /&gt;&lt;br /&gt;This is a perennial nuisance. Not exactly difficult to solve and yet something I find myself solving over and over in different tests and different projects.&lt;br /&gt;&lt;br /&gt;I've come up with what I think is a pretty good and re-usable solution. It allows you to specify messages if you want to, or just use the message code if it's not something you care about in a particular test. As an aside, at a unit test level, I think testing that the correct message &lt;em&gt;code&lt;/em&gt; is being used is probably the right thing to do; I'd leave testing actual message text to end-to-end tests.&lt;br /&gt;&lt;br /&gt;Here's an example. Imagine we're testing the following controller that displays a simple greeting:&lt;script src="http://gist.github.com/595061.js?file=GreetingController.groovy"&gt;&lt;/script&gt;&lt;noscript&gt;&lt;pre&gt;class GreetingController {&lt;br /&gt;    def index = {&lt;br /&gt;        [message: message(code: "greeting.message", args: [params.name])]&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;/noscript&gt;&lt;br /&gt;&lt;br /&gt;Here's a spec that shows the behaviour both when a message is specified and when it isn't:&lt;script src="http://gist.github.com/595061.js?file=GreetingControllerSpec.groovy"&gt;&lt;/script&gt;&lt;noscript&gt;&lt;pre&gt;import grails.plugin.spock.*&lt;br /&gt;import org.springframework.context.*&lt;br /&gt;import org.springframework.context.support.*&lt;br /&gt;import spock.lang.*&lt;br /&gt;&lt;br /&gt;class GreetingControllerSpec extends ControllerSpec {&lt;br /&gt;&lt;br /&gt;    @Shared def messageSource = new StaticMessageSource()&lt;br /&gt;    @Shared def pirateEnglish = new Locale("en", "BV")&lt;br /&gt;&lt;br /&gt;    def setupSpec() {&lt;br /&gt;        messageSource.useCodeAsDefaultMessage = true&lt;br /&gt;        messageSource.addMessage "greeting.message", pirateEnglish, "Ahoy there {0}!"&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    def setup() {&lt;br /&gt;        mockMessageTag(controller, messageSource)&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @Unroll&lt;br /&gt;    def "greeting is rendered by index action"() {&lt;br /&gt;        given:&lt;br /&gt;        if (name) controller.params.name = name&lt;br /&gt;        if (locale) controller.request.addPreferredLocale(locale)&lt;br /&gt;&lt;br /&gt;        expect:&lt;br /&gt;        controller.index() == [message: message]&lt;br /&gt;&lt;br /&gt;        where:&lt;br /&gt;        name  | locale        | message&lt;br /&gt;        null  | null          | "greeting.message"&lt;br /&gt;        "Rob" | null          | "greeting.message"&lt;br /&gt;        "Rob" | pirateEnglish | "Ahoy there Rob!"&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // in reality this would be static imported from a helper class&lt;br /&gt;    static void mockMessageTag(artefact, MessageSource messageSource) {&lt;br /&gt;        artefact.metaClass.message = { attrs -&gt;&lt;br /&gt;            messageSource.getMessage(attrs.code, attrs.args as Object[], delegate.request.locale)&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;/noscript&gt;&lt;br /&gt;&lt;br /&gt;A few things to note:&lt;ol&gt;&lt;li&gt;The stubbed message tag returns the code if there is no message defined&lt;/li&gt;&lt;li&gt;message arguments are ignored unless there is a message defined&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;Although in the example I've used &lt;a href="http://spockframework.org/"&gt;Spock&lt;/a&gt;, this technique would work equally well with &lt;a href="http://grails.org/doc/latest/guide/9.%20Testing.html#9.1%20Unit%20Testing"&gt;JUnit tests extending &lt;em&gt;ControllerUnitTestCase&lt;/em&gt;&lt;/a&gt;. It will also work just as well for tag libs tests extending &lt;em&gt;TagLibUnitTestCase&lt;/em&gt; or &lt;em&gt;TagLibSpec&lt;/em&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-6986033872730769314?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/6986033872730769314/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=6986033872730769314' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/6986033872730769314'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/6986033872730769314'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2010/09/stubbing-access-to-gmessage-tag-in-unit.html' title='Stubbing access to the g:message tag in unit tests'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-3078089869464889473</id><published>2010-08-12T22:46:00.005+01:00</published><updated>2010-08-12T23:51:27.623+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails scripts'/><category scheme='http://www.blogger.com/atom/ns#' term='scaffolding'/><category scheme='http://www.blogger.com/atom/ns#' term='spock'/><category scheme='http://www.blogger.com/atom/ns#' term='events'/><title type='text'>Auto-generate Spock specs for Grails artifacts</title><content type='html'>When creating artifacts such as domain classes, controllers and tag libs Grails generates a &lt;em&gt;JUnit&lt;/em&gt; test case. If, like me, you're digging writing specifications with &lt;a href="http://spockframework.org/"&gt;Spock&lt;/a&gt; you'd probably rather have Grails generate one of those. The last thing I want is to manually transform every generated test case into a specification for every artifact I create.&lt;br /&gt;&lt;br /&gt;It's very simple to create a &lt;em&gt;CreateUnitSpec&lt;/em&gt; or &lt;em&gt;CreateIntegrationSpec&lt;/em&gt; script with a template specification. Hooking in to the other types of artifact creation turned out to be fiddlier. Each &lt;em&gt;create-*&lt;/em&gt; command calls a Closure called &lt;em&gt;createUnitTest&lt;/em&gt;. Reassigning that Closure should be the solution. The trick is in figuring out where that can be done.&lt;br /&gt;&lt;br /&gt;Any time one of its &lt;a href="http://gant.codehaus.org/"&gt;Gant&lt;/a&gt; targets is invoked the Grails build system fires an event. You can respond to those events by declaring a closure called &lt;code&gt;event&amp;lt;target name&amp;gt;Start&lt;/code&gt; in &lt;code&gt;scripts/_Events.groovy&lt;/code&gt;. The only Gant target directly invoked when an artifact is created is called &lt;em&gt;'default'&lt;/em&gt;. It is possible to intercept that although that means the event handler will be invoked any time &lt;strong&gt;any&lt;/strong&gt; Gant target called &lt;em&gt;'default'&lt;/em&gt; runs. For this purpose that's no problem since we're just overriding a closure in the build binding.&lt;br /&gt;&lt;br /&gt;The other factor is that the superclass for the unit test is specified by the individual &lt;em&gt;create-*&lt;/em&gt; scripts (or defaulted to &lt;em&gt;GrailsUnitTestCase&lt;/em&gt;). Rather than having to override those scripts as well, I've just mapped the non-standard unit test superclasses to the Spock equivalents.&lt;br /&gt;&lt;br /&gt;Here's the code for your &lt;code&gt;_Events.groovy&lt;/code&gt; script:&lt;script src="http://gist.github.com/521675.js?file=_Events.groovy"&gt;&lt;/script&gt;&lt;noscript&gt;&lt;pre&gt;eventDefaultStart = {&lt;br /&gt;    createUnitTest = { Map args = [:] -&gt;&lt;br /&gt;        def superClass&lt;br /&gt;        // map unit test superclass to Spock equivalent&lt;br /&gt;        switch(args["superClass"]) {&lt;br /&gt;            case "ControllerUnitTestCase":&lt;br /&gt;                superClass = "ControllerSpec"&lt;br /&gt;                break&lt;br /&gt;            case "TagLibUnitTestCase":&lt;br /&gt;                superClass = "TagLibSpec"&lt;br /&gt;                break&lt;br /&gt;            default:&lt;br /&gt;                superClass = "UnitSpec"&lt;br /&gt;        }&lt;br /&gt;        createArtifact name: args["name"], suffix: "${args['suffix']}Spec", type: "Spec", path: "test/unit", superClass: superClass&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;/noscript&gt;&lt;br /&gt;The template specification should be placed in &lt;code&gt;src/templates/artifacts/Spec.groovy&lt;/code&gt; and is simply:&lt;script src="http://gist.github.com/521675.js?file=Spec.groovy"&gt;&lt;/script&gt;&lt;noscript&gt;&lt;pre&gt;@artifact.package@import spock.lang.*&lt;br /&gt;import grails.plugin.spock.*&lt;br /&gt;&lt;br /&gt;class @artifact.name@ extends @artifact.superclass@ {&lt;br /&gt;    def "feature method"() {&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;/noscript&gt;&lt;br /&gt;It goes without saying that this is a slightly hairy and it would be great if Grails provided a proper hook for overriding the test generation. I can live with some fun-size evil in &lt;em&gt;_Events.groovy&lt;/em&gt; for the sake of the convenience of getting template specs for all my artifacts, though.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-3078089869464889473?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/3078089869464889473/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=3078089869464889473' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/3078089869464889473'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/3078089869464889473'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2010/08/auto-generate-spock-specs-for-grails.html' title='Auto-generate Spock specs for Grails artifacts'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-2280160591178201158</id><published>2010-07-10T14:30:00.006+01:00</published><updated>2010-07-10T14:41:55.176+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='jquery'/><category scheme='http://www.blogger.com/atom/ns#' term='joda time'/><category scheme='http://www.blogger.com/atom/ns#' term='html5'/><title type='text'>Rendering Grails Joda-Time date inputs cross browser with HTML5, jQuery and Modernizr</title><content type='html'>&lt;p&gt;Yesterday I released a new version of the Grails &lt;a href="http://grails.org/plugin/joda-time"&gt;Joda-Time plugin&lt;/a&gt; that includes support for the various new &lt;a href="http://diveintohtml5.org/forms.html#type-date" title="HTML5 Date pickers"&gt;date and time input types&lt;/a&gt; in the HTML5 standard. Right now only &lt;a href="http://opera.com" title="Opera web browser"&gt;Opera&lt;/a&gt; supports these types with proper date-picker type controls, the other browsers just render them as text inputs. However this doesn&amp;#8217;t mean you can&amp;#8217;t or shouldn&amp;#8217;t start using them right away. There&amp;#8217;s a very handy JavaScript library called &lt;a href="http://www.modernizr.com/"&gt;Modernizr&lt;/a&gt; that you can use to detect the features supported by the client&amp;#8217;s browser and render alternatives using script. In this post I&amp;#8217;m going to walk through how to combine the Joda-Time plugin, Modernizr and the &lt;a href="http://jqueryui.com/demos/datepicker/"&gt;jQuery datepicker&lt;/a&gt; to render an HTML5 &lt;em&gt;date&lt;/em&gt; input field that will bind to a &lt;em&gt;LocalDate&lt;/em&gt; property on a domain object.&lt;/p&gt;&lt;h2 id="install_the_joda_time_plugin"&gt;Install the Joda-Time plugin&lt;/h2&gt;&lt;p&gt;If you don&amp;#8217;t currently have version 1.1+ of the Joda-Time plugin installed, run &lt;code&gt;grails install-plugin joda-time&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Once the plugin is installed you will need to enable HTML5 support so that data binding will use the HTML5 date/time formats. Simply add the following to your &lt;em&gt;Config.groovy&lt;/em&gt;&lt;/p&gt;&lt;pre&gt;jodatime.format.html5 = true&lt;br /&gt;&lt;/pre&gt;&lt;h2 id="create_a_domain_class_with_a_localdate_property"&gt;Create a domain class with a LocalDate property&lt;/h2&gt;&lt;p&gt;For this example I&amp;#8217;ll create a simple domain class representing a person:&lt;/p&gt;&lt;pre&gt;import org.joda.time.*&lt;br /&gt;import org.joda.time.contrib.hibernate.*&lt;br /&gt;&lt;br /&gt;class Person {&lt;br /&gt;    String name&lt;br /&gt;    LocalDate birthdate&lt;br /&gt;    static mapping = {&lt;br /&gt;        birthdate type: PersistentLocalDate&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;If you have default mappings set up (which the Joda-Time plugin will attempt to do for you when it installs) then you can omit the &lt;em&gt;mapping&lt;/em&gt; block but I&amp;#8217;ve included it for completeness.&lt;/p&gt;&lt;p&gt;Execute &lt;code&gt;grails generate-all Person&lt;/code&gt; to create a controller and scaffolded views for the &lt;em&gt;Person&lt;/em&gt; class. Finally change the &lt;em&gt;create.gsp&lt;/em&gt; and &lt;em&gt;edit.gsp&lt;/em&gt; files to use an HTML5 input instead of the standard Grails date picker tag. Replace the &lt;code&gt;&amp;lt;g:datePicker name="birthdate"&amp;hellip;&lt;/code&gt; with this:&lt;/p&gt;&lt;pre&gt;&amp;lt;joda:dateField name="birthdate" value="${personInstance.birthdate}"/&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;In the unlikely event that all your site&amp;#8217;s visitors are using Opera then your work is done at this point. However right now anyone using another browser will have to type in the &lt;em&gt;birthdate&lt;/em&gt; value in the correct format in order to get the forms to submit properly which isn&amp;#8217;t the friendliest user experience.&lt;/p&gt;&lt;h2 id="install_jquery_and_jquery_ui"&gt;Install jQuery and jQuery-UI&lt;/h2&gt;&lt;p&gt;You can include jQuery and jQuery-UI by simply downloading the JavaScript files into your app, or linking to them on Google. Alternatively you can use the Grails plugins. If you want to go the plugin route this is what you will need to do. First install the plugins:&lt;/p&gt;&lt;pre&gt;grails install-plugin jquery-ui&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The jQuery plugin is installed automatically by the jQuery-UI plugin.&lt;/p&gt;&lt;p&gt;Then you will need to add the libraries to your SiteMesh template (or you could include it just on the relevant pages, it doesn&amp;#8217;t matter). Add the following in the &lt;em&gt;head&lt;/em&gt; section:&lt;/p&gt;&lt;pre&gt;&amp;lt;g:javascript library="jquery" plugin="jquery"/&amp;gt;&lt;br /&gt;&amp;lt;jqui:resources components="datepicker" mode="normal" /&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;h2 id="install_modernizr"&gt;Install Modernizr&lt;/h2&gt;&lt;p&gt;Download Modernizr and put it in &lt;em&gt;web-app/js/modernizr&lt;/em&gt;. You can link to the script direct from there or define a library by adding this to &lt;em&gt;BootStrap.groovy&lt;/em&gt;:&lt;/p&gt;&lt;pre&gt;import org.codehaus.groovy.grails.plugins.web.taglib.JavascriptTagLib&lt;br /&gt;&lt;br /&gt;class BootStrap {&lt;br /&gt;    def init = { servletContext -&amp;gt;&lt;br /&gt;         JavascriptTagLib.LIBRARY_MAPPINGS.modernizr = ["modernizr/modernizr-1.5.min"]&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Then include Modernizr in your SiteMesh template by adding the following in the &lt;em&gt;head&lt;/em&gt; section:&lt;/p&gt;&lt;pre&gt;&amp;lt;g:javascript library="modernizr"/&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;To get Modernizr to work its magic you should add a &lt;code&gt;class="no-js"&lt;/code&gt; to the &lt;em&gt;html&lt;/em&gt; element at the top of your SiteMesh template. Modernizr will replace this when the document loads with a whole bunch of classes that it uses to detect the various features supported by the browser.&lt;/p&gt;&lt;h2 id="bind_the_jquery_ui_datepicker_to_the_field"&gt;Bind the jQuery-UI datepicker to the field&lt;/h2&gt;&lt;p&gt;The last step is to ensure that any time a user hits the page with a browser that doesn&amp;#8217;t support a native widget for the &lt;em&gt;date&lt;/em&gt; input type they get a jQuery datepicker instead. To do this create a JavaScript file and link to it from your SiteMesh template or the pages using &lt;em&gt;date&lt;/em&gt; inputs. The script simply needs to contain the following code:&lt;/p&gt;&lt;pre&gt;$(document).ready(function() {&lt;br /&gt;    if (!Modernizr.inputtypes.date) {&lt;br /&gt;        $("input[type=date]").datepicker({dateFormat: $.datepicker.W3C});&lt;br /&gt;    }&lt;br /&gt;});&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;What this does is create a function that runs on page load that uses Modernizr to determine if the &lt;em&gt;date&lt;/em&gt; input type is supported and if not initialises a jQuery-UI datepicker for &lt;em&gt;every&lt;/em&gt; &lt;code&gt;&amp;lt;input type="date"&amp;hellip;&lt;/code&gt; found in the page. The &lt;code&gt;dateFormat&lt;/code&gt; argument ensures the jQuery widget will update the input with the correct date format when a value is selected.&lt;/p&gt;&lt;p&gt;It&amp;#8217;s that simple. Now the &lt;em&gt;create&lt;/em&gt; and &lt;em&gt;edit person&lt;/em&gt; pages will use the native &lt;em&gt;date&lt;/em&gt; input widget when the visitor&amp;#8217;s browser supports one and the jQuery widget when it doesn&amp;#8217;t.&lt;/p&gt;&lt;p&gt;So how does it look? Here's a screenshot of the page in Firefox when a visitor has focused the &lt;em&gt;date&lt;/em&gt; input:&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_fh9xwLFYBUw/TDh2YQnv0KI/AAAAAAAACoQ/3ToRH0Ga3iI/s1600/firefox.png" imageanchor="1" style="margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_fh9xwLFYBUw/TDh2YQnv0KI/AAAAAAAACoQ/3ToRH0Ga3iI/s320/firefox.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p style="clear: both;"&gt;Here's the same thing rendered in Opera using the native datepicker widget (yes, you could be forgiven for thinking the jQuery version is prettier):&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_fh9xwLFYBUw/TDh2akA7KeI/AAAAAAAACoY/73k5rC-uWww/s1600/opera.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_fh9xwLFYBUw/TDh2akA7KeI/AAAAAAAACoY/73k5rC-uWww/s320/opera.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p style="clear: both;"&gt;With a little adaptation the same thing can be done for the other input types; &lt;em&gt;month&lt;/em&gt;, &lt;em&gt;week&lt;/em&gt;, &lt;em&gt;time&lt;/em&gt;, &lt;em&gt;datetime&lt;/em&gt; and &lt;em&gt;datetime-local&lt;/em&gt;. Of those &lt;em&gt;month&lt;/em&gt; should work perfectly by adding this to your script:&lt;/p&gt;&lt;pre&gt;if (!Modernizr.inputtypes.month) {&lt;br /&gt;    $("input[type=month]").datepicker({dateFormat: 'yy-mm');&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Other types would require different widgets to enable users to input the time portion of the value. There are several jQuery based options available. Of course, instead of jQuery you could use &lt;a href="http://developer.yahoo.com/yui/calendar/"&gt;YUI&lt;/a&gt;, &lt;a href="http://script.aculo.us/"&gt;script.aculo.us&lt;/a&gt; or any other date/time widgets. I&amp;#8217;ve gone with jQuery because I&amp;#8217;m familiar with it and the initialisation is beautifully simple even if you&amp;#8217;ve got a number of different inputs on a page.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-2280160591178201158?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/2280160591178201158/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=2280160591178201158' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/2280160591178201158'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/2280160591178201158'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2010/07/rendering-date-inputs-cross-browser_10.html' title='Rendering Grails Joda-Time date inputs cross browser with HTML5, jQuery and Modernizr'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_fh9xwLFYBUw/TDh2YQnv0KI/AAAAAAAACoQ/3ToRH0Ga3iI/s72-c/firefox.png' height='72' width='72'/><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-1543143696627102823</id><published>2010-06-29T16:27:00.001+01:00</published><updated>2010-06-29T17:36:14.395+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gorm'/><title type='text'>Acyclic relationship validation in Grails</title><content type='html'>A common domain class use-case is for a self-referential relationship that must not be circular (a &lt;a href="http://en.wikipedia.org/wiki/Directed_acyclic_graph"&gt;directed acyclic graph&lt;/a&gt;). For example, a &lt;em&gt;Person&lt;/em&gt; class may have a &lt;em&gt;parent&lt;/em&gt; property that is a many-to-one relationship with another &lt;em&gt;Person&lt;/em&gt; instance. However a given &lt;em&gt;Person&lt;/em&gt; cannot be his own &lt;em&gt;parent&lt;/em&gt; or ancestor.&lt;br /&gt;&lt;br /&gt;We're using just such a relationship for trees of pages that inherit certain characteristics from their ancestors. In order to validate that our users aren't setting up circular references I implemented the following constraint:&lt;script src="http://gist.github.com/457351.js?file=AcyclicConstraint.groovy"&gt;&lt;/script&gt;&lt;noscript&gt;&lt;pre&gt;import org.codehaus.groovy.grails.validation.AbstractConstraint&lt;br /&gt;import org.springframework.validation.Errors&lt;br /&gt;&lt;br /&gt;class AcyclicConstraint extends AbstractConstraint {&lt;br /&gt;&lt;br /&gt; static final String DEFAULT_MESSAGE_CODE = "default.acyclic.violation.message"&lt;br /&gt; static final String NAME = "acyclic"&lt;br /&gt;&lt;br /&gt; private boolean validateConstraint&lt;br /&gt;&lt;br /&gt; protected void processValidate(Object target, Object propertyValue, Errors errors) {&lt;br /&gt;  if (validateConstraint &amp;&amp; propertyValue) {&lt;br /&gt;   if (isCyclic(target, propertyValue)) {&lt;br /&gt;    def args = [constraintPropertyName, constraintOwningClass, propertyValue] as Object[]&lt;br /&gt;    rejectValue(target, errors, DEFAULT_MESSAGE_CODE, "${NAME}.violation", args)&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; void setParameter(Object constraintParameter) {&lt;br /&gt;  if (!(constraintParameter instanceof Boolean)) {&lt;br /&gt;   throw new IllegalArgumentException("Parameter for constraint [$NAME] of property [$constraintPropertyName] of class [$constraintOwningClass] must be a boolean value")&lt;br /&gt;  }&lt;br /&gt;  validateConstraint = constraintParameter&lt;br /&gt;  super.setParameter(constraintParameter)&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; boolean supports(Class type) { true }&lt;br /&gt;&lt;br /&gt; String getName() { NAME }&lt;br /&gt;&lt;br /&gt; private boolean isCyclic(original, node) {&lt;br /&gt;  boolean cyclic = false&lt;br /&gt;  while (node != null) {&lt;br /&gt;   if (node.id == original.id) {&lt;br /&gt;    cyclic = true&lt;br /&gt;    break&lt;br /&gt;   }&lt;br /&gt;   node = node."$propertyName"&lt;br /&gt;  }&lt;br /&gt;  return cyclic&lt;br /&gt; }&lt;br /&gt;}&lt;/pre&gt;&lt;/noscript&gt;Then I just needed to register my new constraint by adding &lt;code&gt;ConstrainedProperty.registerNewConstraint(AcyclicConstraint.NAME, AcyclicConstraint)&lt;/code&gt; to &lt;em&gt;grails-app/conf/spring/resources.groovy&lt;/em&gt;. Using the constraint is as simple as this:&lt;pre&gt;class Person {&lt;br /&gt;&lt;br /&gt;    String name&lt;br /&gt;    Person parent&lt;br /&gt;&lt;br /&gt;    static constraints = {&lt;br /&gt;        parent acyclic: true&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;The constraint can be mixed with others such as &lt;code&gt;nullable: true&lt;/code&gt;. The really nice thing is that the constraint implementation doesn't reference any of my domain classes directly, meaning it can be re-used in any other domain class.&lt;br /&gt;&lt;br /&gt;When you're using similar validation logic in multiple classes defining a constraint like this is a much better option than using a &lt;em&gt;validator&lt;/em&gt; closure and like many things in Grails it turns out to be pretty easy to implement.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-1543143696627102823?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/1543143696627102823/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=1543143696627102823' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/1543143696627102823'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/1543143696627102823'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2010/06/acyclic-relationship-validation-in.html' title='Acyclic relationship validation in Grails'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-6026224676521361623</id><published>2010-06-24T06:57:00.001+01:00</published><updated>2010-06-28T09:08:51.631+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gorm'/><category scheme='http://www.blogger.com/atom/ns#' term='joda time'/><title type='text'>Defaulting Joda Time Hibernate Types with Grails</title><content type='html'>Grails 1.2 added the ability to define default Hibernate mappings that apply to all GORM classes. It turns out this is incredibly useful if you're using Joda-Time types instead of &lt;em&gt;java.util.Date&lt;/em&gt; in your domain objects. Previously you had to specify the Hibernate user type for every single field, like this:&lt;pre&gt;import org.joda.time.*&lt;br /&gt;import org.joda.time.contrib.hibernate.*&lt;br /&gt;&lt;br /&gt;DateTime dateCreated&lt;br /&gt;DateTime lastUpdated&lt;br /&gt;LocalDate birthday&lt;br /&gt;&lt;br /&gt;static mapping = {&lt;br /&gt;    dateCreated type: PersistentDateTime&lt;br /&gt;    lastUpdated type: PersistentDateTime&lt;br /&gt;    birthday type: PersistentLocalDate&lt;br /&gt;}&lt;/pre&gt;Now you can just add this to your &lt;em&gt;Config.groovy&lt;/em&gt; once and do away with the type mappings in the individual classes:&lt;pre&gt;grails.gorm.default.mapping = {&lt;br /&gt;    "user-type" type: PersistentDateTime, class: DateTime&lt;br /&gt;    "user-type" type: PersistentLocalDate, class: LocalDate&lt;br /&gt;}&lt;/pre&gt;&lt;strong&gt;Correction:&lt;/strong&gt; I had previously posted that the method call in the default mapping DSL could be anything, but on further investigation it turns out it has to be &lt;em&gt;user-type&lt;/em&gt;. Apologies for the error.&lt;br /&gt;&lt;br /&gt;I'll look into the possibility of the Joda-Time plugin doing this itself to make things even easier.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-6026224676521361623?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/6026224676521361623/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=6026224676521361623' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/6026224676521361623'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/6026224676521361623'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2010/06/defaulting-joda-time-hibernate-types.html' title='Defaulting Joda Time Hibernate Types with Grails'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-4222061629973681271</id><published>2010-06-15T14:18:00.005+01:00</published><updated>2010-06-16T09:06:58.260+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails plugins'/><category scheme='http://www.blogger.com/atom/ns#' term='firefox'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='selenium'/><title type='text'>Export Selenium IDE scripts for Grails</title><content type='html'>Thanks to the &lt;a href="http://adam.goucher.ca/?p=1352"&gt;documentation&lt;/a&gt; provided on &lt;a href="http://adam.goucher.ca/"&gt;Adam Goucher's blog&lt;/a&gt; I've created a simple Firefox plugin that extends the &lt;a href="http://seleniumhq.org/projects/ide/"&gt;Selenium IDE&lt;/a&gt; and adds formatters that allow you to export a script as a &lt;a href="http://robfletcher.github.com/grails-selenium-rc/docs/manual/index.html"&gt;Grails Selenium RC&lt;/a&gt; test case. You have the option of JUnit 3 (extends &lt;em&gt;GroovyTestCase&lt;/em&gt;, uses &lt;em&gt;assertEquals&lt;/em&gt;) or JUnit 4 (doesn't extend anything, uses annotations and &lt;em&gt;assertThat&lt;/em&gt;) formats.&lt;br /&gt;&lt;br /&gt;I think everything is working. There are some things I'd still like to do:&lt;ul&gt;&lt;li&gt;Custom commands are currently exported as commented out which they don't need to be given Grails Selenium RC test cases can call Javascript extension functions directly.&lt;/li&gt;&lt;li&gt;I haven't yet figured out how to output a command such as &lt;pre&gt;selenium.waitForAlertPresent()&lt;/pre&gt;rather than &lt;pre&gt;selenium.waitFor {&lt;br /&gt;    selenium.isAlertPresent()&lt;br /&gt;}&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;The Firefox plugin is available from &lt;a href="http://bit.ly/daOJpD"&gt;Selenium HQ&lt;/a&gt;. You will need to have Selenium IDE installed for it to work, obviously. Once installed you should find options &lt;ul&gt;&lt;li&gt;&lt;em&gt;Export Test Case As -&gt; Grails Selenium RC (JUnit 3)&lt;/em&gt;&lt;/li&gt;&lt;li&gt;&lt;em&gt;Export Test Case As -&gt; Grails Selenium RC (JUnit 4)&lt;/em&gt;&lt;/ul&gt;have been added to Selenium IDE's &lt;em&gt;File&lt;/em&gt; menu.&lt;br /&gt;&lt;br /&gt;Whilst I would certainly not leave the exported test case as is it's a quick way to get started. From the exported script you can easily refactor out some page objects or helper methods.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-4222061629973681271?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/4222061629973681271/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=4222061629973681271' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/4222061629973681271'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/4222061629973681271'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2010/06/export-selenium-ide-scripts-for-grails.html' title='Export Selenium IDE scripts for Grails'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-8842705423933147303</id><published>2010-05-28T13:27:00.000+01:00</published><updated>2010-05-28T13:27:46.264+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails plugins'/><category scheme='http://www.blogger.com/atom/ns#' term='spring'/><category scheme='http://www.blogger.com/atom/ns#' term='events'/><category scheme='http://www.blogger.com/atom/ns#' term='asynchronous'/><title type='text'>Grails Spring Events Plugin</title><content type='html'>Following on from &lt;a href="http://adhockery.blogspot.com/2010/05/asynchronous-application-events-in.html"&gt;my last post&lt;/a&gt; I've developed a Grails plugin that packages the asynchronous events behaviour up and adds some extra useful functionality.&lt;br /&gt;&lt;br /&gt;In addition to the asynchronous event processing the plugin gives you:&lt;ul&gt;&lt;li&gt;A &lt;em&gt;publishEvent&lt;/em&gt; method attached to all domain classes, controllers and services.&lt;/li&gt;&lt;li&gt;A Hibernate session bound to the listener thread for the duration of the notification so that listeners can access lazy-loaded properties, etc.&lt;/li&gt;&lt;li&gt;The ability to have a "retry policy" for certain types of failed notifications on individual listeners. This is particularly useful for listeners that do things like invoking external web-services that may be periodically unavailable.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;To install the plugin just use:&lt;pre&gt;grails install-plugin spring-events&lt;/pre&gt;&lt;br /&gt;The code and some more detailed documentation is on &lt;a href="http://github.com/robfletcher/grails-spring-events"&gt;GitHub&lt;/a&gt;. I'll be migrating the docs to the plugin's page on grails.org soon.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-8842705423933147303?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/8842705423933147303/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=8842705423933147303' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/8842705423933147303'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/8842705423933147303'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2010/05/grails-spring-events-plugin.html' title='Grails Spring Events Plugin'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-5730054459239590518</id><published>2010-05-03T21:59:00.003+01:00</published><updated>2010-05-04T06:56:34.147+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='spring'/><category scheme='http://www.blogger.com/atom/ns#' term='events'/><category scheme='http://www.blogger.com/atom/ns#' term='asynchronous'/><title type='text'>Asynchronous application events in Grails</title><content type='html'>On the project for my current client we've been using JMS in a rather na&amp;iuml;ve way for some time now. We've also experienced a certain amount of pain getting JMS and ActiveMQ configured correctly. However, all we're really using JMS for is asynchronous event broadcasting. Essentially we have a handful actions such as flushing hardware caches and notifying external systems that take place when a document changes. We don't want these things blocking the request thread when users save data.&lt;br /&gt;&lt;br /&gt;After wrestling with JMS one too many times we decided to take a look at Spring's event framework instead. It turns out it's extremely easy to use for these kinds of asynchronous notifications in a Grails application.&lt;br /&gt;&lt;br /&gt;Essentially any artefact can publish an event to the Spring application context. A simple publishing service can be implemented like this:&lt;pre&gt;import org.springframework.context.*&lt;br /&gt;&lt;br /&gt;class EventService implements ApplicationContextAware {&lt;br /&gt;&lt;br /&gt;    boolean transactional = false&lt;br /&gt;&lt;br /&gt;    ApplicationContext applicationContext&lt;br /&gt;&lt;br /&gt;    void publish(ApplicationEvent event) {&lt;br /&gt;        println "Raising event '$event' in thread ${Thread.currentThread().id}"&lt;br /&gt;        applicationContext.publishEvent(event)&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;So a Grails domain class can then do something like this:&lt;pre&gt;def eventService&lt;br /&gt;&lt;br /&gt;void afterInsert() {&lt;br /&gt;    eventService.publish(new DocumentEvent(this, "created"))&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void afterUpdate() {&lt;br /&gt;    eventService.publish(new DocumentEvent(this, "updated"))&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void afterDelete() {&lt;br /&gt;    eventService.publish(new DocumentEvent(this, "deleted"))&lt;br /&gt;}&lt;/pre&gt;Grails services make ideal &lt;a href="http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/context/ApplicationListener.html"&gt;&lt;em&gt;ApplicationListener&lt;/em&gt;&lt;/a&gt; implementations. As services are singleton Spring beans they are automatically discovered by Spring's event system without any configuration required. For example:&lt;pre&gt;import org.springframework.context.*&lt;br /&gt;&lt;br /&gt;class EventLoggingService implements ApplicationListener&amp;lt;DocumentEvent&amp;gt; {&lt;br /&gt;&lt;br /&gt;    boolean transactional = false&lt;br /&gt;&lt;br /&gt;    void onApplicationEvent(DocumentEvent event) {&lt;br /&gt;        println "Recieved event '$event' in thread ${Thread.currentThread().id}"&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;Of course, multiple listeners can respond to the same events.&lt;br /&gt;&lt;br /&gt;If you run the code you will notice that by default Spring's event system processes events synchronously. The &lt;em&gt;EventService&lt;/em&gt; and &lt;em&gt;ApplicationListener&lt;/em&gt; will print out the same Thread &lt;em&gt;id&lt;/em&gt;. This is not ideal if any of the listener implementations might take any time. Luckily it's easy to override the &lt;a href="http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/context/event/ApplicationEventMulticaster.html"&gt;&lt;em&gt;ApplicationEventMulticaster&lt;/em&gt;&lt;/a&gt; bean in &lt;code&gt;resources.groovy&lt;/code&gt; so that it uses a thread pool:&lt;pre&gt;import java.util.concurrent.*&lt;br /&gt;import org.springframework.context.event.*&lt;br /&gt;&lt;br /&gt;beans = {&lt;br /&gt;    applicationEventMulticaster(SimpleApplicationEventMulticaster) {&lt;br /&gt;        taskExecutor = Executors.newCachedThreadPool()&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;Running the code again will show the event being published in one thread and consumed in another. If you have multiple listeners each one will be executed in its own thread.&lt;br /&gt;&lt;br /&gt;Oddly, I would have thought it was possible to override the &lt;em&gt;taskExecutor&lt;/em&gt; property of the default &lt;em&gt;ApplicationEventMulticaster&lt;/em&gt; in &lt;code&gt;Config.groovy&lt;/code&gt; using Grails' &lt;a href="http://grails.org/doc/latest/guide/14.%20Grails%20and%20Spring.html#14.6%20Property%20Override%20Configuration" title="Property Override Configuration in the Grails User Guide"&gt;property override configuration&lt;/a&gt;, but I found the following didn't work:&lt;pre&gt;beans {&lt;br /&gt;    applicationEventMulticaster {&lt;br /&gt;        taskExecutor = Executors.newCachedThreadPool()&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-5730054459239590518?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/5730054459239590518/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=5730054459239590518' title='14 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/5730054459239590518'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/5730054459239590518'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2010/05/asynchronous-application-events-in.html' title='Asynchronous application events in Grails'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>14</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-2056404987559742666</id><published>2010-05-03T07:59:00.002+01:00</published><updated>2010-05-03T08:23:07.236+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails plugins'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='selenium'/><title type='text'>Selenium RC plugin v1.0</title><content type='html'>The Selenium RC plugin for Grails has hit version 1.0 with: &lt;ul&gt;&lt;li&gt;Firefox 3.6 support&lt;/li&gt;&lt;li&gt;grabbing of screenshots on test failures&lt;/li&gt;&lt;li&gt;the ability to call JavaScript user extensions on the &lt;em&gt;selenium&lt;/em&gt; object as though they were regular Groovy methods&lt;/li&gt;&lt;/ul&gt;among other features. Check out the documentation at &lt;a href="http://robfletcher.github.com/grails-selenium-rc"&gt;http://robfletcher.github.com/grails-selenium-rc&lt;/a&gt; and install with &lt;code&gt;grails install-plugin selenium-rc&lt;/code&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-2056404987559742666?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/2056404987559742666/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=2056404987559742666' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/2056404987559742666'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/2056404987559742666'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2010/05/selenium-rc-plugin-v10.html' title='Selenium RC plugin v1.0'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-4619713461677399238</id><published>2010-05-03T06:35:00.001+01:00</published><updated>2010-05-03T06:38:31.803+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hudson'/><title type='text'>Building your app on Hudson with Multiple Grails versions</title><content type='html'>For my Grails plugins I generally write a test project (or more than one). I thought it would be useful to be able to run these against multiple versions of Grails on my build server so I can spot any incompatibilities with the versions the plugin is supposed to support.&lt;br /&gt;&lt;br /&gt;Using &lt;a href="http://hudson-ci.org/"&gt;Hudson&lt;/a&gt; this turned out to be pretty straightforward.&lt;br /&gt;&lt;br /&gt;You will need all the Grails versions you want to test against installed on your Hudson box. I put them in &lt;code&gt;/opt&lt;/code&gt; so replace that with wherever you have them in the steps below. Also, if you want the builds to run in parallel and will be running any functional tests you'll need the &lt;a href="http://wiki.hudson-ci.org/display/HUDSON/Port+Allocator+Plugin"&gt;Hudson Port Allocator plugin&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Start by creating a new job in Hudson and choosing &lt;em&gt;"Build multi-configuration project"&lt;/em&gt;.&lt;/li&gt;&lt;li&gt;The configuration dialog has an extra section &lt;em&gt;"Configuration Matrix"&lt;/em&gt; where you can set up the different config combinations that will run. We're just interested in varying the Grails version so check the &lt;em&gt;"Axes"&lt;/em&gt; and create a new axis named &lt;em&gt;"GRAILS_VERSION"&lt;/em&gt; with the different versions you want in the &lt;em&gt;"values"&lt;/em&gt; box, e.g. "&lt;code&gt;1.2.0 1.2.1 1.2.2 1.3.0.RC2&lt;/code&gt;"&lt;/li&gt;&lt;li&gt;Set up your source code repository and build triggers as you would for any other project.&lt;/li&gt;&lt;li&gt;If you want to run the builds in parallel and are running any functional tests you will need to make sure that Grails starts up on a unique port. In the &lt;em&gt;"Build environment"&lt;/em&gt; section add a new &lt;em&gt;"Plain TCP port"&lt;/em&gt; named &lt;em&gt;"GRAILS_PORT"&lt;/em&gt;. If you're running anything else that needs a port such as a Selenium server you'll need one for that as well.&lt;/li&gt;&lt;li&gt;Add an &lt;em&gt;"Execute shell"&lt;/em&gt; build step. Unfortunately the Hudson Grails plugin does not allow you to use a variable to specify the Grails version so you'll have to go old-school:&lt;br /&gt;&lt;pre&gt;export GRAILS_HOME=/opt/grails-$GRAILS_VERSION&lt;br /&gt;export PATH=$GRAILS_HOME/bin:$PATH&lt;br /&gt;# assign Grails a unique port (you can skip this if you're only running unit/integration tests)&lt;br /&gt;export JAVA_OPTS="$JAVA_OPTS -Dserver.port=$GRAILS_PORT"&lt;br /&gt;grails clean&lt;br /&gt;grails upgrade --non-interactive&lt;br /&gt;grails test-app --non-interactive&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;Check &lt;em&gt;"Publish JUnit test result report"&lt;/em&gt; in the &lt;em&gt;"Post-build Actions"&lt;/em&gt; section and specify &lt;code&gt;target/test-reports/*.xml&lt;/code&gt; as the &lt;em&gt;"Test report XMLs"&lt;/em&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;When you run the Hudson job you should see it kick off one sub-job for each Grails version. Each will check out the project, upgrade it to the relevant Grails version and run the tests.&lt;br /&gt;&lt;br /&gt;I have my plugin test projects triggered by the plugin build and have them grab the plugin zip itself from the archived artefacts in the plugin's Hudson job. So I've added this before the &lt;code&gt;grails test-app&lt;/code&gt; step:&lt;pre&gt;grails install-plugin http://my.hudson.server/hudson/job/my-plugin/lastSuccessfulBuild/artifact/my-plugin-1.0.zip --non-interactive&lt;br /&gt;&lt;/pre&gt;There's a &lt;a href="http://jira.codehaus.org/browse/GRAILS-6223"&gt;bug&lt;/a&gt; in Grails 1.3.0.RC2 that means you will need to split this into a &lt;code&gt;wget&lt;/code&gt; followed by installing the zip from a file path rather than a URL. This is fixed in trunk so won't be a problem in Grails 1.3 final.&lt;br /&gt;&lt;br /&gt;If you're using SVN I think you may need to revert any changes the &lt;code&gt;grails upgrade&lt;/code&gt; has made to &lt;code&gt;application.properties&lt;/code&gt;, etc. otherwise you'll get merge conflicts on the next run. This does not seem to be a problem with Git.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-4619713461677399238?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/4619713461677399238/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=4619713461677399238' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/4619713461677399238'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/4619713461677399238'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2010/05/building-your-app-on-hudson-with.html' title='Building your app on Hudson with Multiple Grails versions'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-4960719509417336613</id><published>2010-04-21T14:26:00.002+01:00</published><updated>2010-04-21T14:27:51.881+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='junit4'/><title type='text'>A Grails JUnit 4 test template</title><content type='html'>&lt;p&gt;Grails 1.3 upgrades the bundles JUnit to the newer JUnit 4 API. However, the test template used to generate classes by the Grails &lt;em&gt;create-*&lt;/em&gt; scripts is still very JUnit 3-ish. Here's a replacement that will generate a skeleton test using JUnit 4 conventions:&lt;p&gt;&lt;script src="http://gist.github.com/373794.js?file=Tests.groovy"&gt;&lt;/script&gt;&lt;noscript&gt;&lt;pre&gt;@artifact.package@import grails.test.*&lt;br /&gt;import org.junit.*&lt;br /&gt;import static org.junit.Assert.*&lt;br /&gt;import static org.hamcrest.CoreMatchers.*&lt;br /&gt;import static org.junit.matchers.JUnitMatchers.*&lt;br /&gt;&lt;br /&gt;class @artifact.name@ {&lt;br /&gt;    @Before void setUp() {&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @After void tearDown() {&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @Test void something() {&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;/noscript&gt;&lt;p&gt;To use this just run &lt;code&gt;grails install-templates&lt;/code&gt; then copy the contents over the file &lt;em&gt;src/templates/artifacts/Tests.groovy&lt;/em&gt;. You can delete anything else in the &lt;em&gt;src/templates&lt;/em&gt; directory that you don't need. Then every time you use a Grails command such as &lt;code&gt;grails create-service foo&lt;/code&gt; the generated test will use the JUnit 4 template.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-4960719509417336613?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/4960719509417336613/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=4960719509417336613' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/4960719509417336613'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/4960719509417336613'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2010/04/grails-junit-4-test-template.html' title='A Grails JUnit 4 test template'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-6769373730304133684</id><published>2010-03-17T06:53:00.003Z</published><updated>2010-03-17T06:58:24.554Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='data binding'/><title type='text'>Customising collection binding in Grails</title><content type='html'>Following up on my earlier post about &lt;a href="http://adhockery.blogspot.com/2010/02/using-custom-data-binder-with-grails.html"&gt;using custom &lt;tt&gt;PropertyEditor&lt;/tt&gt; implementations to bind association properties&lt;/a&gt; I started looking into the options for custom binding one-to-many associations.&lt;br /&gt;&lt;br /&gt;For example, tags, as seen on many sites (including Blogger) would typically be modelled as a &lt;tt&gt;Set&lt;/tt&gt; of either &lt;tt&gt;String&lt;/tt&gt; or some kind of &lt;em&gt;Tag&lt;/em&gt; domain object. With &lt;em&gt;tag&lt;/em&gt; functionality we really don't want to be selecting tags using a multi-select combo box. It would be ridiculously huge and hard to find anything in it. An auto-completer that recognises commas as delimiters would be the way to go. Script.aculo.us has an &lt;a href="http://wiki.github.com/madrobby/scriptaculous/ajax-autocompleter"&gt;AJAX Autocompleter&lt;/a&gt; that can handle this kind of tokenised input. Similarly, the Grails RichUI plugin offers an &lt;a href="http://grails.org/plugin/richui#AutoComplete"&gt;autocomplete tag&lt;/a&gt; that uses a Yahoo! UI component. There are comparable controls available if you're using jQuery or some other Javascript library. What you will end up with is the browser submitting a single parameter containing a comma-separated String of tag names. The trick is to turn that into a collection of &lt;tt&gt;String&lt;/tt&gt; or &lt;tt&gt;Tag&lt;/tt&gt; domain instances.&lt;br /&gt;&lt;br /&gt;For the former case binding is pretty easy. All you need is a property editor that converts a comma-separated String into a &lt;tt&gt;Set&lt;/tt&gt; of &lt;tt&gt;String&lt;/tt&gt; and &lt;em&gt;vice-versa&lt;/em&gt;:&lt;script src="http://gist.github.com/334988.js"&gt;&lt;/script&gt;&lt;noscript&gt;&lt;pre&gt;class TagListEditor extends PropertyEditorSupport {&lt;br /&gt;    void setAsText(String text) {&lt;br /&gt;        value = text.split(/,\s*/) as Set&lt;br /&gt;    }&lt;br /&gt; &lt;br /&gt;    String getAsText() {&lt;br /&gt;        value?.join(", ")&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;/noscript&gt;&lt;br /&gt;Then just register the editor in your &lt;tt&gt;PropertyEditorRegistrar&lt;/tt&gt; implementation:&lt;pre&gt;registry.registerCustomEditor List, "tags", new TagListEditor()&lt;/pre&gt;&lt;br /&gt;If you've gone the latter route and used a domain object to represent a &lt;em&gt;tag&lt;/em&gt; things have been trickier. Grails didn't allow you to register custom property editors against one-to-many association properties as it considered it knew how to handle such binding.&lt;br /&gt;&lt;br /&gt;I raised and fixed a &lt;a href="http://jira.codehaus.org/browse/GRAILS-5985"&gt;Grails issue&lt;/a&gt; to allow for registering custom editors on one-to-many properties so from 1.2.2 and 1.3-M2 you will be able to use a property editor something like this:&lt;script src="http://gist.github.com/334989.js"&gt;&lt;/script&gt;&lt;noscript&gt;&lt;pre&gt;class TagListEditor extends PropertyEditorSupport {&lt;br /&gt;    void setAsText(String text) {&lt;br /&gt;        value = text.split(/,\s*/).collect {&lt;br /&gt;            Tag.findByName(it) ?: new Tag(name: it)&lt;br /&gt;        } as Set&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    String getAsText() {&lt;br /&gt;        value?.name?.join(", ")&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;/noscript&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-6769373730304133684?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/6769373730304133684/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=6769373730304133684' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/6769373730304133684'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/6769373730304133684'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2010/03/customising-collection-binding-in.html' title='Customising collection binding in Grails'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-4911208502153925941</id><published>2010-03-11T17:50:00.006Z</published><updated>2010-03-12T05:39:55.521Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails plugins'/><category scheme='http://www.blogger.com/atom/ns#' term='hudson'/><category scheme='http://www.blogger.com/atom/ns#' term='continuous integration'/><title type='text'>Grails plugins on Hudson</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_fh9xwLFYBUw/S5ks3ENs8yI/AAAAAAAACbU/vHE684-UsTI/s1600/hudson.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="165" src="http://4.bp.blogspot.com/_fh9xwLFYBUw/S5ks3ENs8yI/AAAAAAAACbU/vHE684-UsTI/s400/hudson.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;Yesterday I spent some time setting up &lt;a href="http://hudson-ci.org/"&gt;Hudson&lt;/a&gt; continuous integration build for my various Grails plugins. It was pretty straightforward but I've &lt;a href="https://twitter.com/wangjammer5/statuses/10269319705"&gt;been asked&lt;/a&gt; to document the steps involved.&lt;br /&gt;&lt;br /&gt;Each plugin has one or more test applications under &lt;code&gt;test/projects&lt;/code&gt; each of which has &lt;code&gt;grails.plugin.location.whatever = "../../.."&lt;/code&gt; in &lt;code&gt;BuildConfig.groovy&lt;/code&gt;. So each plugin CI build needs to run not only the plugin's own unit tests but any integration and/or functional tests included in the test apps as well.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Hudson plugins&lt;/h3&gt;I installed the essential plugins I would need:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The &lt;a href="http://wiki.hudson-ci.org/display/HUDSON/Grails+Plugin"&gt;Grails plugin&lt;/a&gt; makes building Grails projects much easier and allows you to build against multiple versions of Grails.&lt;/li&gt;&lt;li&gt;The &lt;a href="http://wiki.hudson-ci.org/display/HUDSON/Git+Plugin"&gt;Git plugin&lt;/a&gt; enables Hudson to pull from a Git repository such as GitHub.&lt;/li&gt;&lt;li&gt;The &lt;a href="http://wiki.hudson-ci.org/display/HUDSON/Github+Plugin"&gt;GitHub plugin&lt;/a&gt; adds links to the GitHub project in the Hudson build.&lt;/li&gt;&lt;li&gt;The &lt;a href="http://wiki.hudson-ci.org/display/HUDSON/ChuckNorris+Plugin"&gt;Chuck Norris plugin&lt;/a&gt; encourages you to keep your tests from failing.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Configuring Grails&lt;/h3&gt;Under &lt;em&gt;Manage Hudson -&amp;gt; Configure System&lt;/em&gt; there is a &lt;em&gt;Grails Builder&lt;/em&gt; section where I entered the name and path of the various versions of Grails installed on the build box.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Connecting to GitHub&lt;/h3&gt;In the project configuration:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;I pasted the GitHub project URL in the &lt;em&gt;Github project&lt;/em&gt; field (shown if you have the GitHub plugin installed).&lt;/li&gt;&lt;li&gt;Under &lt;em&gt;Source Code Management&lt;/em&gt; I selected &lt;em&gt;Git&lt;/em&gt; then pasted the read-only repository URL into the &lt;em&gt;URL of repository&lt;/em&gt; field.&lt;/li&gt;&lt;li&gt;I entered &lt;em&gt;master&lt;/em&gt; in the &lt;em&gt;Branch Specifier&lt;/em&gt; field as I've seen Hudson do odd things picking up changes from other branches before. I don't really need this behaviour and haven't had time to investigate it further yet.&lt;/li&gt;&lt;li&gt;I ticked &lt;em&gt;Poll SCM&lt;/em&gt; under &lt;em&gt;Build Triggers&lt;/em&gt; then set a cron expression of &lt;code&gt;*/5 * * * *&lt;/code&gt; so Hudson will poll GitHub every 5 minutes.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Grails build steps&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Select &lt;em&gt;Build with Grails&lt;/em&gt; from the &lt;em&gt;Add build step&lt;/em&gt; drop down, then:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Select the &lt;em&gt;Grails Installation&lt;/em&gt; you want to use.&lt;/li&gt;&lt;li&gt;Enter the &lt;em&gt;Targets&lt;/em&gt; to run. These are the Grails commands that Hudson will execute. For example, I entered &lt;code&gt;"test-app unit: -clean --non-interactive" package-plugin&lt;/code&gt; for the to run unit tests then package the plugin. The quotes allow arguments to be passed to individual targets so I'm telling the &lt;em&gt;test-app&lt;/em&gt; phase to build clean and run non-interactively (i.e. Grails won't ask about things like installing or uninstalling plugins).&lt;/li&gt;&lt;li&gt;The other fields can be left blank for now.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;Add further Grails build steps for test applications. The only difference in configuring these is that the targets will likely be different and &lt;em&gt;Project Base Directory&lt;/em&gt; needs to be set to the relative path where the test apps lives, e.g. &lt;code&gt;test/projects/content-caching&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Isolating each build&lt;/h3&gt;One thing I found is that it's probably a good idea to specify separate working directory for each build. I found that simultaneous builds would stomp over each other's compiled classes otherwise. This is particularly an issue for me where I have a build for the &lt;em&gt;Selenium RC&lt;/em&gt; plugin whilst one of the test apps for the &lt;em&gt;Springcache&lt;/em&gt; plugin uses the latest &lt;em&gt;Selenium RC&lt;/em&gt; release to run tests.&lt;br /&gt;&lt;br /&gt;Hudson provides various &lt;a href="http://wiki.hudson-ci.org/display/HUDSON/Building+a+software+project#Buildingasoftwareproject-HudsonSetEnvironmentVariables"&gt;environment variables&lt;/a&gt; so I just set &lt;em&gt;grails.work.dir&lt;/em&gt; to &lt;code&gt;/tmp/.grails/${JOB_NAME}&lt;/code&gt; in every case.&lt;br /&gt;&lt;br /&gt;The other consideration is the port that Grails applications will use. If you are running any kind of functional tests the Grails application will start and it each Hudson job needs to use a separate server port or simultaneous jobs will experience port contention. The server port is also configured in the Grails build step. I've just assigned a different one to each job but I couldn't think of a particularly clever way to automate the port assignment.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Test reports&lt;/h3&gt;Under &lt;em&gt;Post-build Actions&lt;/em&gt; I ticked &lt;em&gt;Publish JUnit test result report&lt;/em&gt; then entered a comma-separated set of paths to the XML reports generated by each build step. For example, the &lt;em&gt;Springcache&lt;/em&gt; plugin has the following reports configured:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;target/test-reports/*.xml,test/projects/springcache-test/target/test-reports/*.xml,test/projects/content-caching/target/test-reports/*.xml&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;That's picking up the root plugin's unit test reports and the reports generated by the &lt;em&gt;springcache-test&lt;/em&gt; and &lt;em&gt;content-caching&lt;/em&gt; test applications. Hudson does a good job of merging these together into a unified test report.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Running tests that need a browser&lt;/h3&gt;Some of my tests use &lt;em&gt;Selenium RC&lt;/em&gt; which drives a real browser. Given that Hudson is running on a headless box I had to get the display exported to a box with an X Windows environment.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Still to do&lt;/h3&gt;Right now all the plugins are building against Grails 1.2.1 only so the next task is to set up parallel builds using Grails 1.3-RC1. Ideally I would like to use Hudson's multi-configuration project capability to do that but I haven't had a chance to look into it yet. I'd also like to use Gradle to build the various project with one build step but I'd lose the convenience in switching Grails versions that the Hudson Grails plugin gives me.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-4911208502153925941?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/4911208502153925941/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=4911208502153925941' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/4911208502153925941'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/4911208502153925941'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2010/03/grails-plugins-on-hudson.html' title='Grails plugins on Hudson'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_fh9xwLFYBUw/S5ks3ENs8yI/AAAAAAAACbU/vHE684-UsTI/s72-c/hudson.png' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-5597278614303482778</id><published>2010-03-05T06:42:00.003Z</published><updated>2010-03-05T06:44:06.842Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='caching'/><category scheme='http://www.blogger.com/atom/ns#' term='grails plugins'/><title type='text'>Page fragment caching with Grails Springcache plugin</title><content type='html'>&lt;p&gt;Yesterday I released the new version of the Springcache plugin for Grails. The new feature this brings to the table is page fragment caching driven by annotations on controller actions. The feature is based on &lt;a href="http://ehcache.org/documentation/web_caching.html"&gt;EhCache Web&lt;/a&gt; and is even simpler and more powerful than the full page caching &lt;a href="http://adhockery.blogspot.com/2010/02/full-page-caching-in-grails-with.html"&gt;I blogged about recently&lt;/a&gt;. With the page fragment caching feature you can:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Define &lt;tt&gt;@Cacheable&lt;/tt&gt; and &lt;tt&gt;@CacheFlush&lt;/tt&gt; annotations on controller actions.&lt;/li&gt;&lt;li&gt;Have SiteMesh decorate cached and uncached output alike.&lt;/li&gt;&lt;li&gt;Use SiteMesh to mix dynamic page sections with cached sections.&lt;/li&gt;&lt;li&gt;Use SiteMesh and &lt;tt&gt;&amp;lt;g:include&amp;gt;&lt;/tt&gt; to have multiple areas of the page that are cached and flushed independently of one another.&lt;/li&gt;&lt;li&gt;Cache the output of controller actions that use content negotiation separately according to the requested format.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;There are some examples in the &lt;a href="http://grails.org/plugin/springcache"&gt;plugin documentation&lt;/a&gt; and the &lt;a href="http://github.com/robfletcher/grails-springcache"&gt;plugin source code&lt;/a&gt; has &lt;a href="http://github.com/robfletcher/grails-springcache/tree/master/test/projects/content-caching/"&gt;a test project&lt;/a&gt; with a variety of page fragment caching mechanisms used and tested.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-5597278614303482778?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/5597278614303482778/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=5597278614303482778' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/5597278614303482778'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/5597278614303482778'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2010/03/page-fragment-caching-with-grails.html' title='Page fragment caching with Grails Springcache plugin'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-606571697020185595</id><published>2010-02-25T13:04:00.002Z</published><updated>2010-03-17T08:53:23.102Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='gorm'/><category scheme='http://www.blogger.com/atom/ns#' term='spring'/><category scheme='http://www.blogger.com/atom/ns#' term='data binding'/><title type='text'>Using a custom data binder with Grails domain objects</title><content type='html'>Yesterday I read a &lt;a href="http://blog.armbruster-it.de/2010/01/customizing-grails-data-binding-with-a-groovy-propertyeditor/"&gt;post by Stefan Armbruster&lt;/a&gt; on how to register a custom data binder to lookup Grails domain objects by any arbitrary property. I wanted to go a little further so that I could not only bind existing domain instances but create new ones as well.&lt;br /&gt;&lt;br /&gt;For example, let's say I have &lt;em&gt;Artist&lt;/em&gt; and &lt;em&gt;Album&lt;/em&gt; domain classes where &lt;em&gt;Artist hasMany Albums&lt;/em&gt; and &lt;em&gt;Album belongsTo Artist&lt;/em&gt;. &lt;em&gt;Artist&lt;/em&gt; has a &lt;em&gt;name&lt;/em&gt; property that is unique. On my &lt;em&gt;create album&lt;/em&gt; page I want to be able to type in the artist name and have the &lt;em&gt;save&lt;/em&gt; action in the controller automatically lookup an existing &lt;em&gt;Artist&lt;/em&gt; instance or create a new one if it doesn't exist. Doing this I don't want to have to add or change anything in the &lt;em&gt;save&lt;/em&gt; action itself - I could theoretically use dynamic scaffolding.&lt;br /&gt;&lt;br /&gt;Adapting Stefan's &lt;em&gt;PropertyEditor&lt;/em&gt; implementation I created this: &lt;script src="http://gist.github.com/315705.js?file=DomainClassLookupPropertyEditor.groovy"&gt;&lt;/script&gt;&lt;noscript&gt;&lt;pre&gt;import java.beans.PropertyEditorSupport&lt;br /&gt;import org.apache.commons.lang.StringUtils&lt;br /&gt; &lt;br /&gt;class DomainClassLookupPropertyEditor extends PropertyEditorSupport {&lt;br /&gt; &lt;br /&gt;    Class domainClass&lt;br /&gt;    String property&lt;br /&gt; &lt;br /&gt;    String getAsText() {&lt;br /&gt;        value."$property"&lt;br /&gt;    }&lt;br /&gt; &lt;br /&gt;    void setAsText(String text) {&lt;br /&gt;        value = domainClass."findBy${StringUtils.capitalize(property)}"(text)&lt;br /&gt;        if (!value) {&lt;br /&gt;            value = domainClass.newInstance((property): text)&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;/noscript&gt;&lt;br /&gt;The crucial change is the &lt;code&gt;if (!value)&lt;/code&gt; block which creates the new instance and populates the relevant property.&lt;br /&gt;&lt;br /&gt;To make everything work I just need to:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Add the &lt;em&gt;PropertyEditorRegistrar&lt;/em&gt; and place it in &lt;tt&gt;resources.groovy&lt;/tt&gt; as per Stefan's post.&lt;/li&gt;&lt;li&gt;Have a text input or autocompleter with the name &lt;em&gt;"artist"&lt;/em&gt; in my &lt;em&gt;create album&lt;/em&gt; form.&lt;/li&gt;&lt;li&gt;Add &lt;code&gt;artist cascade: "save-update"&lt;/code&gt; to the &lt;em&gt;mapping&lt;/em&gt; block in &lt;em&gt;Album&lt;/em&gt; so that when the &lt;em&gt;Album&lt;/em&gt; is saved the new &lt;em&gt;Album&lt;/em&gt; will get saved as well.&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-606571697020185595?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/606571697020185595/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=606571697020185595' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/606571697020185595'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/606571697020185595'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2010/02/using-custom-data-binder-with-grails.html' title='Using a custom data binder with Grails domain objects'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-4267809439994636304</id><published>2010-02-23T12:47:00.000Z</published><updated>2010-02-23T12:47:18.122Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='caching'/><title type='text'>Full page caching in Grails with Ehcache-Web</title><content type='html'>I'm on the verge of releasing a new version of the &lt;a href="http://grails.org/plugin/springcache"&gt;Springcache plugin&lt;/a&gt; that will feature a pretty cool new annotation-driven page fragment caching feature based on &lt;a href="http://ehcache.org/documentation/web_caching.html"&gt;Ehcache-web&lt;/a&gt;. However one of the things that came up during discussions on the mailing list was full page caching. I mentioned that it was pretty straightforward and promised to blog about how to do it, so…&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Install Ehcache-web&lt;/h3&gt;Add the following to your dependencies in BuildConfig.groovy:&lt;br /&gt;&lt;pre&gt;runtime("net.sf.ehcache:ehcache-web:2.0.0") {&lt;br /&gt; excludes "ehcache-core"&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Install Grails templates&lt;/h3&gt;Run: &lt;code&gt;grails install-templates&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Set up a page caching filter&lt;/h3&gt;Edit &lt;tt&gt;src/templates/war/web.xml&lt;/tt&gt; and add this to the &lt;tt&gt;filters&lt;/tt&gt; section:&lt;br /&gt;&lt;pre&gt;&amp;lt;filter&amp;gt;&lt;br /&gt; &amp;lt;filter-name&amp;gt;MyPageCachingFilter&amp;lt;/filter-name&amp;gt;&lt;br /&gt; &amp;lt;filter-class&amp;gt;net.sf.ehcache.constructs.web.filter.SimplePageCachingFilter&amp;lt;/filter-class&amp;gt;&lt;br /&gt; &amp;lt;init-param&amp;gt;&lt;br /&gt;  &amp;lt;param-name&amp;gt;cacheName&amp;lt;/param-name&amp;gt;&lt;br /&gt;  &amp;lt;param-value&amp;gt;myPageCache&amp;lt;/param-value&amp;gt;&lt;br /&gt; &amp;lt;/init-param&amp;gt;&lt;br /&gt;&amp;lt;/filter&amp;gt;&lt;/pre&gt;And this as the &lt;em&gt;first entry&lt;/em&gt; in the &lt;tt&gt;filter-mappings&lt;/tt&gt; section:&lt;br /&gt;&lt;pre&gt;&amp;lt;filter-mapping&amp;gt;&lt;br /&gt; &amp;lt;filter-name&amp;gt;MyPageCachingFilter&amp;lt;/filter-name&amp;gt;&lt;br /&gt; &amp;lt;url-pattern&amp;gt;/controller/action/*&amp;lt;/url-pattern&amp;gt;&lt;br /&gt; &amp;lt;dispatcher&amp;gt;REQUEST&amp;lt;/dispatcher&amp;gt;&lt;br /&gt;&amp;lt;/filter-mapping&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Configure the cache&lt;/h3&gt;Unfortunately you can't configure the cache in &lt;tt&gt;grails-app/conf/spring/resources.groovy&lt;/tt&gt; using &lt;tt&gt;EhCacheFactoryBean&lt;/tt&gt; instances as the servlet filter initialises before the Spring context. The cache definitions need to be added to a &lt;tt&gt;ehcache.xml&lt;/tt&gt; which would normally be placed in &lt;tt&gt;grails-app/conf&lt;/tt&gt;. Here is an example that works for the filter definitions above:&lt;br /&gt;&lt;pre&gt;&amp;lt;ehcache&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;diskStore path="java.io.tmpdir"/&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;defaultCache&lt;br /&gt;            maxElementsInMemory="10"&lt;br /&gt;            eternal="false"&lt;br /&gt;            timeToIdleSeconds="5"&lt;br /&gt;            timeToLiveSeconds="10"&lt;br /&gt;            overflowToDisk="true"&lt;br /&gt;            /&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;cache name="myPageCache"&lt;br /&gt;           maxElementsInMemory="10"&lt;br /&gt;           eternal="false"&lt;br /&gt;           timeToIdleSeconds="10000"&lt;br /&gt;           timeToLiveSeconds="10000"&lt;br /&gt;           overflowToDisk="true"&amp;gt;&lt;br /&gt;    &amp;lt;/cache&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/ehcache&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;You will need to add another &lt;tt&gt;filter&lt;/tt&gt; and &lt;tt&gt;filter-mapping&lt;/tt&gt; and potentially another cache for each URL pattern you want to cache separately.&lt;br /&gt;&lt;br /&gt;Full page caching is fine for simple pages but isn't as flexible as fragment caching. For example, any authenticated state (such as a &lt;em&gt;"Welcome back xxx"&lt;/em&gt; label) on the page would get cached across all users. Because Grails uses &lt;a href="http://www.opensymphony.com/sitemesh/"&gt;Sitemesh&lt;/a&gt; and has the &lt;tt&gt;&lt;a href="http://grails.org/doc/latest/ref/Tags/include.html"&gt;&amp;lt;g:include&amp;gt;&lt;/a&gt;&lt;/tt&gt; tag for including output from other controllers a fragment caching solution is a good fit. The 1.2 release of the Springcache plugin will add fragment caching functionality. However, I can imagine using full-page caching like this for things like RSS feeds.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-4267809439994636304?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/4267809439994636304/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=4267809439994636304' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/4267809439994636304'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/4267809439994636304'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2010/02/full-page-caching-in-grails-with.html' title='Full page caching in Grails with Ehcache-Web'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-3287166044287614322</id><published>2010-01-17T20:35:00.002Z</published><updated>2010-01-17T20:39:36.906Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails plugins'/><category scheme='http://www.blogger.com/atom/ns#' term='gradle'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><title type='text'>A Gradle build for Grails plugins with test apps</title><content type='html'>There's a fairly popular technique in Grails plugin development where the plugin has 'test apps' stored in &lt;tt&gt;test/projects/*&lt;/tt&gt;, each of which references the plugin by including &lt;code&gt;grails.plugin.location."my-plugin" = "../../.."&lt;/code&gt; in its &lt;em&gt;BuildConfig.groovy&lt;/em&gt;. Doing this allows you as a plugin developer to:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Automate tests for sample projects using the plugin with significantly different configurations.&lt;/li&gt;&lt;li&gt;Test using domain classes, controllers, etc. that shouldn't be packaged with the plugin.&lt;/li&gt;&lt;li&gt;Test drive, changing code in both the test app and the plugin without the need to use &lt;code&gt;grails package-plugin&lt;/code&gt; or &lt;code&gt;grails install-plugin&lt;/code&gt; to pick up changes.&lt;/li&gt;&lt;/ul&gt;The downside is that to run all the plugin project's tests it's necessary to run the plugin's own tests, then change directory into each of the test apps and run their tests. Continuous integration config is also fiddlier for the same reason.&lt;br /&gt;&lt;br /&gt;I wanted to find a way to automate this so I could run all my plugins' tests with a single command. I could write a &lt;em&gt;bash&lt;/em&gt; script or an &lt;em&gt;Ant&lt;/em&gt; build I guess, or even use &lt;em&gt;maven &lt;small&gt;&amp;lt;shudder&amp;gt;&lt;/small&gt;&lt;/em&gt;. However keeping things in Groovy-land I decided to try using &lt;em&gt;&lt;a href="http://www.gradle.org/"&gt;Gradle&lt;/a&gt;&lt;/em&gt; which I've been meaning to look into for a while now. I saw &lt;a href="http://skillsmatter.com/podcast/java-jee/gradle-deep-dive"&gt;Hans Dockter's presentation&lt;/a&gt; on &lt;em&gt;Gradle&lt;/em&gt; at the &lt;a href="http://skillsmatter.com/event/java-jee/groovy-grails-exchange-2009/wd-184"&gt;London Groovy &amp; Grails Exchange&lt;/a&gt; back in December and was impressed with how terse and expressive the syntax is, especially compared to XML based formats. Unfortunately one thing &lt;em&gt;Gradle&lt;/em&gt; doesn't grok yet is Grails.&lt;br /&gt;&lt;br /&gt;The solution I've come up with is based on &lt;a href="http://www.mail-archive.com/user@gradle.codehaus.org/msg01871.html"&gt;a post by Helmut Denk&lt;/a&gt; on the &lt;em&gt;gradle-user&lt;/em&gt; list. Gradle just uses &lt;a href="http://ant.apache.org/manual/CoreTasks/exec.html"&gt;Ant's exec task&lt;/a&gt; to shell out and execute the appropriate Grails command. Combining this with Gradle's multi-project build support I now have plugin builds that can be run with &lt;code&gt;gradle test&lt;/code&gt; that will automatically descend into the test apps under &lt;em&gt;test/projects/*&lt;/em&gt;.&lt;br /&gt;&lt;br /&gt;The &lt;em&gt;build.gradle&lt;/em&gt; file at the root of the project defines &lt;em&gt;clean&lt;/em&gt; and &lt;em&gt;test&lt;/em&gt; tasks: &lt;script src="http://gist.github.com/279554.js?file=build.gradle"&gt;&lt;/script&gt; The &lt;em&gt;test&lt;/em&gt; task will run the plugin's unit tests. The &lt;em&gt;clean&lt;/em&gt; task is defined just once for all projects as there's no difference in how it is done - a nice examply of Gradle's &lt;a href="http://en.wikipedia.org/wiki/Don't_repeat_yourself"&gt;DRY&lt;/a&gt;-ness.&lt;br /&gt;&lt;br /&gt;Then in &lt;em&gt;settings.gradle&lt;/em&gt; I tell Gradle where to find the various sub-projects: &lt;script src="http://gist.github.com/279554.js?file=settings.gradle"&gt;&lt;/script&gt;&lt;br /&gt;Finally each test app has it's own &lt;em&gt;build.gradle&lt;/em&gt; that defines its &lt;em&gt;test&lt;/em&gt; task: &lt;script src="http://gist.github.com/279554.js?file=springcache-test.gradle"&gt;&lt;/script&gt; This is only necessary if the test apps run tests differently to the plugin - here my app is running integration rather than unit tests - otherwise I could have defined &lt;em&gt;test&lt;/em&gt; in the same DRY manner as &lt;em&gt;clean&lt;/em&gt;.&lt;br /&gt;&lt;br /&gt;The process is not as fast as it could be if Grails were wired in to Gradle properly. &lt;tt&gt;gradle clean test&lt;/tt&gt; for the Springcache plugin and its two test apps takes just over 2 minutes on my MBP. Also, my Gradle-fu leaves a lot to be desired right now so I'm sure there are improvements that could be made with the way I'm handling the sub-projects. But, for the purposes of a pre-commit test run or Hudson build this works pretty well.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-3287166044287614322?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/3287166044287614322/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=3287166044287614322' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/3287166044287614322'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/3287166044287614322'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2010/01/gradle-build-for-grails-plugins-with.html' title='A Gradle build for Grails plugins with test apps'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-7993782667499642014</id><published>2010-01-04T21:22:00.004Z</published><updated>2010-01-04T21:38:54.135Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails upgrade'/><category scheme='http://www.blogger.com/atom/ns#' term='gorm'/><title type='text'>Upgrading Grails 1.1 -&gt; 1.2</title><content type='html'>&lt;p&gt;We've just successfully upgraded our app from Grails 1.1 to &lt;a href="http://www.grails.org/1.2+Release+Notes"&gt;1.2&lt;/a&gt; and pushed it to our QA environment. I thought I'd write up some of the issues we encountered in case anyone is bashing their heads against them.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Custom constraints that execute queries&lt;/h3&gt;&lt;p&gt;Grails 1.2 now executes domain object validation on any unsaved objects when the Hibernate session flushes. One upshot of this is that if you have a custom constraint that executes a query you can end up with a &lt;em&gt;StackOverflowError&lt;/em&gt;; the query causes the session to flush, causing the object to be validated, causing the query to run, causing the session to flush, etc.&lt;/p&gt;&lt;p&gt;The solution is to use one of the new domain class dynamic methods &lt;em&gt;&lt;a href="http://grails.org/doc/latest/ref/Domain%20Classes/withNewSession.html"&gt;withNewSession&lt;/a&gt;&lt;/em&gt; to execute the query in a separate Hibernate session.&lt;/p&gt;&lt;p&gt;For example, we have a domain class where only a single instance can exist in a 'live' state. A simple &lt;em&gt;&lt;a href="http://grails.org/doc/latest/ref/Constraints/unique.html"&gt;unique&lt;/a&gt;&lt;/em&gt; constraint won't work as any number of instances can exist in other states. The final constraint looks something like this:&lt;/p&gt;&lt;pre&gt;static constraints = {&lt;br /&gt;    state validator: { value, self -&gt;&lt;br /&gt;        boolean valid = true&lt;br /&gt;        if (value == State.LIVE) {&lt;br /&gt;            Homepage.withNewSession {&lt;br /&gt;                valid = Homepage.countByStateAndIdNotEqual(State.LIVE, self.id) == 0&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        return valid&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Errors set outside constraints&lt;/h3&gt;&lt;p&gt;The new validation on flush behaviour also caused us a more subtle and difficult to trace problem. One of our controllers checks that a date/time property on a domain class instance is in the future when the instance is saved. Doing this in a constraint isn't desirable as it makes it awkward to set up test data or re-save instances in other contexts - the rule really only applies to the domain class when the user creates or updates it on the one particular form.&lt;/p&gt;&lt;p&gt;The validation code in the controller looks something like this:&lt;/p&gt;&lt;pre&gt;domainInstance.validate()&lt;br /&gt;if (domainInstance.goLiveTime &lt; new Date()) {&lt;br /&gt;    domainInstance.rejectValue "goLiveTime", "min.notMet"&lt;br /&gt;}&lt;br /&gt;if (!domainInstance.hasErrors() &amp;&amp; domainInstance.save()) {&lt;br /&gt;    // redirect&lt;br /&gt;} else {&lt;br /&gt;    // re-render form with errors&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;When upgrading one of our Selenium tests started failing as, although the save was failing, the error message did not get rendered on the form. What was happening is that at the end of the controller action the entity was not saved as it had errors but Hibernate attempted to flush and triggered re-validation which wiped out the error the controller had set.&lt;/p&gt;&lt;p&gt;If &lt;em&gt;&lt;a href="http://grails.org/doc/latest/ref/Domain%20Classes/save.html"&gt;save&lt;/a&gt;&lt;/em&gt; had been called and validation failed then the object would have been made read-only so Hibernate would not attempt to flush it. My solution was to do this explicitly in the &lt;em&gt;else&lt;/em&gt; block before rendering the form using &lt;code&gt;&lt;a href="http://grails.org/doc/latest/api/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsHibernateUtil.html#setObjectToReadyOnly(java.lang.Object,%20org.hibernate.SessionFactory)"&gt;GrailsHibernateUtil.setObjectToReadOnly(domainInstance, sessionFactory)&lt;/a&gt;&lt;/code&gt;. It's certainly not ideal that the controller should be aware of this kind of low-level detail so some refactoring is in order here, but it solved the problem.&lt;/p&gt;&lt;h3&gt;Specifying fetch modes on associations in criteria queries&lt;/h3&gt;&lt;p&gt;We have one particularly nasty query that retrieves a domain object instance and loads an entire hierarchy of associations using several &lt;code&gt;&lt;a href="http://grails.org/doc/latest/api/grails/orm/HibernateCriteriaBuilder.html#fetchMode(java.lang.String,%20org.hibernate.FetchMode)"&gt;fetchMode "property", FetchMode.JOIN&lt;/a&gt;&lt;/code&gt; in the criteria query. For example if &lt;em&gt;Author&lt;/em&gt; has many &lt;em&gt;books&lt;/em&gt; and each &lt;em&gt;Book&lt;/em&gt; has many &lt;em&gt;chapters&lt;/em&gt; the query previously looked like:&lt;/p&gt;&lt;pre&gt;Author.withCriteria {&lt;br /&gt;    // some criteria&lt;br /&gt;    fetchMode "books", FetchMode.JOIN&lt;br /&gt;    fetchMode "chapters", FetchMode.JOIN&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;This always seemed syntactically odd as it appears that &lt;em&gt;chapters&lt;/em&gt; is a property of &lt;em&gt;Author&lt;/em&gt; when it is in fact a property of each member of &lt;em&gt;Author.books&lt;/em&gt;. In Grails 1.2 the syntax makes much more sense as you nest the &lt;em&gt;fetchMode&lt;/em&gt; declarations just as you would other criteria. So the example above would become:&lt;/p&gt;&lt;pre&gt;Author.withCriteria {&lt;br /&gt;    // some criteria&lt;br /&gt;    fetchMode "books", FetchMode.JOIN&lt;br /&gt;    books {&lt;br /&gt;        fetchMode "chapters", FetchMode.JOIN&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;h3&gt;Date binding format&lt;/h3&gt;&lt;p&gt;Date binding now uses a fixed format of &lt;em&gt;yyyy-MM-dd HH:mm:ss.S&lt;/em&gt; rather than the short format of the request locale. We have a couple of forms where dates are entered as text rather than using a date picker or rich control and the users (and our tests) expect to be able to enter dates as &lt;em&gt;dd/MM/yy&lt;/em&gt;. In order to keep this functionality working I had to create a class that implements &lt;em&gt;&lt;a href="http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/beans/PropertyEditorRegistrar.html"&gt;PropertyEditorRegistrar&lt;/a&gt;&lt;/em&gt; and deploy it in &lt;em&gt;grails-app/conf/spring/resources.groovy&lt;/em&gt;. The class registers a custom date editor using the required format.&lt;/p&gt;&lt;p&gt;Because the custom property editor registration happens on a per-request basis it would be simple to use the same technique to allow users to enter dates in the locale format they are used to (Americans with their crazy month-day-year format and everyone else with something sensible, for example).&lt;/p&gt;&lt;h3&gt;Setting String values in &lt;em&gt;g:set&lt;/em&gt; tags&lt;/h3&gt;&lt;p&gt;One of the main features of Grails 1.2 is the enhanced GSP rendering performance. One way this was achieved as I understand it is that mutable streams are used rather than immutable &lt;em&gt;String&lt;/em&gt; instances where possible. One minor change I had to make to support this was changing &lt;em&gt;g:set&lt;/em&gt; tags in the format &lt;code&gt;&amp;lt;g:set var="name"&amp;gt;${value}&amp;lt;/g:set&amp;gt;&lt;/code&gt; to &lt;code&gt;&amp;lt;g:set var="name" value="${value}"/&amp;gt;&lt;/code&gt;Variable created in the first manner are now instances of &lt;em&gt;&lt;a href="http://grails.org/doc/latest/api/org/codehaus/groovy/grails/web/util/StreamCharBuffer.html"&gt;StreamCharBuffer&lt;/a&gt;&lt;/em&gt; rather than &lt;em&gt;java.lang.String&lt;/em&gt; which sometimes caused problems when they were used later.&lt;/p&gt;&lt;h3&gt;Flash scope and null values&lt;/h3&gt;&lt;p&gt;The &lt;em&gt;&lt;a href="http://grails.org/doc/latest/ref/Controllers/flash.html"&gt;flash&lt;/a&gt;&lt;/em&gt; scope object available to controllers is now an instance of &lt;em&gt;ConcurrentHashMap&lt;/em&gt; which means none of its keys can map to &lt;em&gt;null&lt;/em&gt;. There were a few places where we were setting &lt;em&gt;flash.message&lt;/em&gt; to the result of a method call that might return &lt;em&gt;null&lt;/em&gt;. I simply ensured the empty string was used instead.&lt;/p&gt;&lt;p&gt;Ultimately the upgrade took a lot less time and effort than when we went from Grails 1.0.3 to 1.1 and we thankfully didn't encounter any blocking issues. The impression I have is that the platform's really maturing nicely. Will be cool to start using some of the new features of 1.2 in the next few weeks.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-7993782667499642014?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/7993782667499642014/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=7993782667499642014' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/7993782667499642014'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/7993782667499642014'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2010/01/upgrading-grails-11-12.html' title='Upgrading Grails 1.1 -&gt; 1.2'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-5651650075747334175</id><published>2010-01-02T12:23:00.000Z</published><updated>2010-01-02T12:23:13.619Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails plugins'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='selenium'/><title type='text'>Selenium RC tests with a running Grails app</title><content type='html'>I &lt;a href="http://adhockery.blogspot.com/2009/12/selenium-rc-tests-with-remote-app.html"&gt;posted recently&lt;/a&gt; about the new remote mode feature of the &lt;a href="http://grails.org/plugin/selenium-rc"&gt;Selenium RC plugin&lt;/a&gt;. One thing I forgot to mention is that this feature can also be used to run your Selenium tests interactively against a running app instance. You can start your app as normal using &lt;code&gt;grails run-app&lt;/code&gt; then either open a second terminal or background the process (&lt;em&gt;Ctrl-Z&lt;/em&gt; in a &lt;em&gt;bash&lt;/em&gt; shell) then use &lt;code&gt;grails -Dselenium.remote=true test-app other:selenium &lt;em&gt;&amp;lt;test name&amp;gt;&lt;/em&gt;&lt;/code&gt; to run individual tests without stopping or re-starting the app. With the app running &lt;em&gt;development&lt;/em&gt; mode you can effectively test-drive using Selenium tests and Grails' artefact reloading capabilities.&lt;br /&gt;&lt;br /&gt;One thing I should clarify is that direct domain class access will &lt;em&gt;not&lt;/em&gt; work in remote mode. I'm thinking about ways to add &lt;a href="http://grails.org/plugin/fixtures"&gt;fixtures&lt;/a&gt; support to the Selenium RC plugin so there's a good alternative approach that will work in remote mode.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-5651650075747334175?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/5651650075747334175/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=5651650075747334175' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/5651650075747334175'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/5651650075747334175'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2010/01/selenium-rc-tests-with-running-grails.html' title='Selenium RC tests with a running Grails app'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-4751369116119615233</id><published>2010-01-01T14:33:00.002Z</published><updated>2010-01-01T15:44:07.305Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='gmock'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><title type='text'>Using GMock to complement Grails mockDomain</title><content type='html'>Since Grails 1.1 we've had pretty good &lt;a href="http://grails.org/doc/latest/guide/single.html#9. Testing"&gt;unit testing support&lt;/a&gt; via &lt;em&gt;GrailsUnitTestCase&lt;/em&gt; and its sub-classes. The &lt;em&gt;mockDomain&lt;/em&gt; method is particularly useful for simulating the various enhancements Grails adds to domain classes. However, there are some domain class capabilities, such as criteria queries and the new &lt;a href="http://grails.org/doc/latest/ref/Domain%20Classes/namedQueries.html"&gt;named queries&lt;/a&gt;, that can't really be simulated by &lt;em&gt;mockDomain&lt;/em&gt;.&lt;br /&gt;&lt;br /&gt;So assuming we're trying to unit test a controller that uses criteria methods or named queries on a domain class how can we enhance the capabilities of &lt;em&gt;mockDomain&lt;/em&gt;? One of my favourite Groovy libraries is &lt;a href="http://gmock.org/"&gt;GMock&lt;/a&gt; which I use in preference to Groovy's built in mock capabilities. One of its really powerful features is the ability to use &lt;a href="http://gmock.org/documentation/0.8.0#Partial_mock"&gt;'partial mocks'&lt;/a&gt;, &lt;em&gt;i.e.&lt;/em&gt; to mock particular methods on a class whilst allowing the rest of the class to continue functioning as normal. This means we can layer a mocked &lt;em&gt;createCriteria&lt;/em&gt;, &lt;em&gt;withCriteria&lt;/em&gt; or named query call on to a domain class that is already enhanced by &lt;em&gt;mockDomain&lt;/em&gt;.&lt;br /&gt;&lt;br /&gt;First off you need to add the GMock dependency to your &lt;em&gt;BuildConfig.groovy&lt;/em&gt;. Since GMock supports &lt;a href="http://code.google.com/p/hamcrest/"&gt;Hamcrest matchers&lt;/a&gt; for matching method arguments you'll probably want those as well:&lt;br /&gt;&lt;pre&gt;    dependencies {&lt;br /&gt;        test "org.gmock:gmock:0.8.0"&lt;br /&gt;        test "org.hamcrest:hamcrest-all:1.0"&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;If you're using an earlier version of Grails you'll need to just grab the jar files and put them in your app's &lt;em&gt;lib&lt;/em&gt; directory.&lt;br /&gt;&lt;br /&gt;Then in your test case you need to import GMock and Hamcrest classes and add an annotation to allow GMock to work:&lt;br /&gt;&lt;pre&gt;    import grails.test.*&lt;br /&gt;    import org.gmock.*&lt;br /&gt;    import static org.hamcrest.Matchers.*&lt;br /&gt;&lt;br /&gt;    @WithGMock&lt;br /&gt;    class MyControllerTests extends ControllerUnitTestCase {&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Adding criteria and named query methods is now fairly simple:&lt;br /&gt;&lt;h4&gt;Mocking a withCriteria method&lt;/h4&gt;&lt;pre&gt;    def results = // whatever you want your criteria query to return&lt;br /&gt;    mock(MyDomain).static.withCriteria(instanceOf(Closure)).returns(results)&lt;br /&gt;    play {&lt;br /&gt;        controller.myAction()&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;Breaking this example down a little&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;code&gt;mock(MyDomain)&lt;/code&gt; establishes a partial mock of the domain class.&lt;/li&gt;&lt;li&gt;&lt;code&gt;instanceOf(Closure)&lt;/code&gt; uses a Hamcrest &lt;em&gt;instanceOf&lt;/em&gt; matcher to assert that the &lt;em&gt;withCriteria&lt;/em&gt; method is called with a single &lt;em&gt;Closure&lt;/em&gt; argument (the bit with all the criteria in).&lt;/li&gt;&lt;li&gt;&lt;code&gt;returns(results)&lt;/code&gt; tells the mock to return the specified results which here would be a list of domain object instances.&lt;/li&gt;&lt;/ol&gt;In this example we're expecting the &lt;em&gt;withCriteria&lt;/em&gt; method to be called just once but GMock supports more complex &lt;a href="http://gmock.org/documentation/0.8.0#Time_matching"&gt;time matching expressions&lt;/a&gt; if the method may be called again.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Mocking a &lt;em&gt;createCriteria&lt;/em&gt; method&lt;/h4&gt;The &lt;em&gt;withCriteria&lt;/em&gt; method returns results directly but &lt;em&gt;createCriteria&lt;/em&gt; is a little more complicated in that it returns a criteria object that has methods such as &lt;em&gt;list&lt;/em&gt;, &lt;em&gt;count&lt;/em&gt; and &lt;em&gt;get&lt;/em&gt;. To simulate this we'll need to have the mocked &lt;em&gt;createCriteria&lt;/em&gt; method return a mocked criteria object.&lt;br /&gt;&lt;pre&gt;    def results = // whatever you want your criteria query to return&lt;br /&gt;    def mockCriteria = mock() {&lt;br /&gt;        list(instanceOf(Closure)).returns(results)&lt;br /&gt;    }&lt;br /&gt;    mock(MyDomain).static.createCriteria().returns(mockCriteria)&lt;br /&gt;    play {&lt;br /&gt;        controller.myAction()&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;This is only a little more complex than the previous example in that it has the mocked &lt;em&gt;list&lt;/em&gt; method on another mock object that is returned by the domain class' &lt;em&gt;createCriteria&lt;/em&gt; method. &lt;code&gt;mock()&lt;/code&gt; provides an un-typed mock object as we really don't care about the type here.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Mocking a named query&lt;/h4&gt;For our purposes named queries are actually pretty similar to &lt;em&gt;createCriteria&lt;/em&gt;.&lt;br /&gt;&lt;pre&gt;    def results = // whatever you want your criteria query to return&lt;br /&gt;    def mockCriteria = mock() {&lt;br /&gt;        list(instanceOf(Closure)).returns(results)&lt;br /&gt;    }&lt;br /&gt;    mock(MyDomain).static.myNamedQuery().returns(mockCriteria)&lt;br /&gt;    play {&lt;br /&gt;        controller.myAction()&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Some other examples:&lt;br /&gt;&lt;h4&gt;Mocking a named query with an argument&lt;/h4&gt;&lt;pre&gt;    mock(MyDomain).static.myNamedQuery("blah").returns(mockCriteria)&lt;br /&gt;&lt;/pre&gt;For simple parameters you don't need to use a Hamcrest matcher - a literal is just fine.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Mocking a &lt;em&gt;withCriteria&lt;/em&gt; call using options&lt;/h4&gt;You can pass an argument map to &lt;em&gt;withCriteria&lt;/em&gt;, &lt;em&gt;e.g.&lt;/em&gt; &lt;code&gt;withCriteria(uniqueResult: true) { /* criteria */ }&lt;/code&gt; will return a single instance rather than a &lt;em&gt;List&lt;/em&gt;. To mock this you will need to expect the &lt;em&gt;Map&lt;/em&gt; as well as the &lt;em&gt;Closure&lt;/em&gt;:&lt;br /&gt;&lt;pre&gt;    def result = // a single domain object instance&lt;br /&gt;    mock(MyDomain).static.withCriteria(uniqueResult: true, instanceOf(Closure)).returns(result)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h4&gt;Mocking criteria that are re-used&lt;/h4&gt;It's fairly common in pagination scenarios to call a &lt;em&gt;list&lt;/em&gt; and &lt;em&gt;count&lt;/em&gt; method on a criteria object. We can just set multiple expectations on the mock criteria object, e.g.&lt;br /&gt;&lt;pre&gt;    def mockCriteria = mock() {&lt;br /&gt;        list(max: 10).returns(results)&lt;br /&gt;        count().returns(999)&lt;br /&gt;    }&lt;br /&gt;    mock(MyDomain).static.myNamedQuery().returns(mockCriteria)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The nice thing about this technique is that it doesn't interfere with any of the enhancements &lt;em&gt;mockDomain&lt;/em&gt; makes to the domain class, so the &lt;em&gt;save&lt;/em&gt;, &lt;em&gt;validate&lt;/em&gt;, etc. methods will still work as will dynamic finders.&lt;br /&gt;&lt;br /&gt;Be aware however, that what we're doing here is &lt;em&gt;mocking out&lt;/em&gt; the criteria queries, not testing them! All the interesting stuff inside the criteria closure is being ignored by the mocks and could, of course, be garbage. Named queries are pretty easy to test by having integration test cases for your domain class. Criteria queries beyond a trivial level of complexity should really be encapsulated in service methods or named queries and integration tested there. Of course, GMock then makes an excellent solution for mocking that service method in your controller unit test.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-4751369116119615233?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/4751369116119615233/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=4751369116119615233' title='14 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/4751369116119615233'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/4751369116119615233'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2010/01/using-gmock-to-complement-grails.html' title='Using GMock to complement Grails mockDomain'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>14</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-5771048642054762466</id><published>2009-12-29T12:18:00.001Z</published><updated>2009-12-29T16:36:47.358Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails plugins'/><category scheme='http://www.blogger.com/atom/ns#' term='selenium'/><title type='text'>Selenium RC tests with a remote app</title><content type='html'>I've just released a new snapshot of the &lt;a href="http://grails.org/plugin/selenium-rc"&gt;Selenium RC plugin&lt;/a&gt;. The main new feature is the ability to run your Selenium tests against a running instance of your application instead of having the application start and stop as part of the test phase. A number of people have requested this. It's really useful for CI environments where you may want to start the app up on a different server from where the tests are being run.&lt;br /&gt;&lt;br /&gt;All you need to do is set &lt;code&gt;selenium.remote = true&lt;/code&gt; in your &lt;em&gt;SeleniumConfig.groovy&lt;/em&gt; and set &lt;code&gt;selenium.url&lt;/code&gt; to the root URL of the server where the app is running. Once this is done you can run tests as normal (note: when remote mode is used Selenium tests run in the &lt;em&gt;other&lt;/em&gt; phase rather than the &lt;em&gt;functional&lt;/em&gt; phase).&lt;br /&gt;&lt;br /&gt;The &lt;em&gt;really&lt;/em&gt; useful thing is that &lt;em&gt;SeleniumConfig.groovy&lt;/em&gt; can contain environment blocks just as other Grails config files can. This means you can enable remote mode in your CI environment but continue to test as normal locally. For example:&lt;br /&gt;&lt;pre&gt;selenium {&lt;br /&gt;    remote = false&lt;br /&gt;    // etc.&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;environments {&lt;br /&gt;    hudson {&lt;br /&gt;        selenium.remote = true&lt;br /&gt;        selenium.url = "http://my.test.server/"&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The plugin release is a snapshot so you need to specify the version explictly: &lt;code&gt;grails install-plugin selenium-rc 0.2-SNAPSHOT&lt;/code&gt; and you need to be using Grails 1.2.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-5771048642054762466?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/5771048642054762466/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=5771048642054762466' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/5771048642054762466'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/5771048642054762466'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2009/12/selenium-rc-tests-with-remote-app.html' title='Selenium RC tests with a remote app'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-6080168974683303618</id><published>2009-12-12T16:49:00.001Z</published><updated>2009-12-12T16:50:48.783Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='caching'/><category scheme='http://www.blogger.com/atom/ns#' term='grails plugins'/><title type='text'>New Springcache Plugin Version</title><content type='html'>After &lt;a href="http://adhockery.blogspot.com/2009/11/springcache-plugin-status.html"&gt;saying it might take me a while&lt;/a&gt; I got stuck in and rewrote the Springcache plugin from scratch. The new version is up now. The plugin now requires Grails 1.2.0-M3 or greater as it's reliant on Spring 3.0.&lt;br /&gt;&lt;br /&gt;The plugin allows you to declare caching and flushing behaviour on service methods (well, any Spring bean methods, but services are typical) using &lt;code&gt;@Cacheable&lt;/code&gt; and &lt;code&gt;@CacheFlush&lt;/code&gt; annotations. This is really useful for service methods that perform long-running or expensive tasks such as retrieving data from web services, network resources, etc. The plugin is less appropriate for service methods that retrieve data using GORM/Hibernate as you could just use the 2nd level cache, although there's nothing stopping you doing so if it makes sense in your domain.&lt;br /&gt;&lt;br /&gt;The documentation and source code are in the usual places. Here's a quick summary of the changes and new features:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;No longer depends on the (discontinued and non-Spring 3 compatible) &lt;a href="https://springmodules.dev.java.net/"&gt;spring-modules-cache&lt;/a&gt; library.&lt;/li&gt;&lt;li&gt;No more mapcache, the plugin now uses &lt;a href="http://ehcache.org/"&gt;ehcache&lt;/a&gt; by default.&lt;/li&gt;&lt;li&gt;Only ehcache is supported directly but it's really easy to implement an adapter for other caching libraries if you need to.&lt;/li&gt;&lt;li&gt;Slightly simplified configuration. Some minor tweaks will be needed if you're upgrading from an earlier version of the plugin.&lt;/li&gt;&lt;li&gt;Bean names are now prefixed with &lt;em&gt;"springcache"&lt;/em&gt; so they're much less likely to clash with other things in your Spring context.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;There has been some interest in some new features such as a taglib for caching chunks of views which I may start looking at shortly.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-6080168974683303618?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/6080168974683303618/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=6080168974683303618' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/6080168974683303618'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/6080168974683303618'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2009/12/new-springcache-plugin-version.html' title='New Springcache Plugin Version'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-2718898559151956179</id><published>2009-11-26T22:56:00.000Z</published><updated>2009-11-26T22:56:25.907Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='caching'/><category scheme='http://www.blogger.com/atom/ns#' term='grails plugins'/><category scheme='http://www.blogger.com/atom/ns#' term='spring'/><title type='text'>Springcache Plugin Status</title><content type='html'>A couple of people have asked me about the &lt;a href="http://grails.org/plugin/springcache"&gt;Springcache plugin&lt;/a&gt; and Grails 1.2. Currently the plugin is not compatible with 1.2-M3 and onwards. The reason for this is that the spring-modules-cache library that the plugin depends on is not compatible with Spring 3.0 which is used by the newest versions of Grails. Not only that but the &lt;a href="https://springmodules.dev.java.net/"&gt;spring-modules project&lt;/a&gt; has been discontinued altogether. There is &lt;a href="http://github.com/astubbs/spring-modules"&gt;a fork of it on Github&lt;/a&gt; but that doesn't look terribly active either. This means that at some point I'm going to have to sit down and write some code to bring the annotation driven caching inside the plugin itself and drop the spring-modules dependency. However, just to compound things the &lt;a href="http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/ch08s09.html#aop-autoproxy-metadata"&gt;Spring documentation on the relevant area&lt;/a&gt; hasn't been updated yet and still references the classes that have been removed from the API which is what's causing the incompatibility in the first place!&lt;br /&gt;&lt;br /&gt;So, it's on my to-do list but don't hold your breath!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-2718898559151956179?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/2718898559151956179/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=2718898559151956179' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/2718898559151956179'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/2718898559151956179'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2009/11/springcache-plugin-status.html' title='Springcache Plugin Status'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-4070742447407848978</id><published>2009-11-21T14:17:00.001Z</published><updated>2009-11-21T14:18:24.307Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Why do Strings behave like a Collection?</title><content type='html'>Mostly I love Groovy but every now and then some behaviour gets on my nerves. For example, why do the iterator methods on String behave as though it was a collections of characters rather than an Object? If I define a method with a dynamic-typed parameter like:&lt;pre&gt;void printNames(names) {&lt;br /&gt;    names.each {&lt;br /&gt;        println it&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;Passing a collection of Strings results in each String being printed. Passing a single String results in each character of the String being printed separately. I would have thought that the Object behaviour was a more appropriate default here (iterators on Object are called once passing the object itself). After all the &lt;code&gt;.chars&lt;/code&gt; property is available if you really want to represent a String as a collection of characters.&lt;br /&gt;&lt;br /&gt;The solution is to override the method:&lt;pre&gt;void printNames(String name) {&lt;br /&gt;    printNames([name])&lt;br /&gt;}&lt;/pre&gt;Unlike in Java dispatch to such overridden methods in Groovy is based on the runtime rather than declared type of the parameter.&lt;br /&gt;&lt;br /&gt;You might think this is a trivial point, but the scenario that keeps biting me is HTTP parameters passed into a Grails controller. If you have multiple inputs with the same name, or a multi-select then sometimes &lt;code&gt;params.x&lt;/code&gt; is a String and sometimes it's a List of Strings. Any code dealing with that parameter has to handle the two cases separately.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-4070742447407848978?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/4070742447407848978/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=4070742447407848978' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/4070742447407848978'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/4070742447407848978'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2009/11/why-do-strings-behave-like-collection.html' title='Why do Strings behave like a Collection&lt;Character&gt;?'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-4419078667735737653</id><published>2009-11-21T06:45:00.002Z</published><updated>2009-11-21T07:14:37.523Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails plugins'/><category scheme='http://www.blogger.com/atom/ns#' term='ggug'/><category scheme='http://www.blogger.com/atom/ns#' term='selenium'/><title type='text'>Slides from GGUG</title><content type='html'>I gave a talk last night at the &lt;a href="http://skillsmatter.com/event/ajax-ria/testing-grails-applications-with-selenium-rc"&gt;London Groovy &amp; Grails User Group&lt;/a&gt; about the &lt;a href="http://grails.org/plugin/selenium-rc"&gt;Selenium RC plugin&lt;/a&gt; and how to use it. I pitched the talk assuming that people were somewhat familiar with &lt;a href="http://seleniumhq.org/docs/"&gt;Selenium&lt;/a&gt; and had probably used the &lt;a href="http://seleniumhq.org/projects/ide/"&gt;Selenium IDE&lt;/a&gt;. I'm not sure if that was the right way to go but the talk went pretty well and people seemed interested in what I had to say. I ended up talking a lot about the &lt;a href="http://code.google.com/p/webdriver/wiki/PageObjects"&gt;page object pattern&lt;/a&gt; and how awesome it is for building manageable suites of Selenium tests.&lt;br /&gt;&lt;br /&gt;I really wanted to show a few quick examples but I had neglected to consider that a &lt;a href="http://store.apple.com/uk/product/MB572Z/A?fnode=MTY1NDA3Ng&amp;mco=MTA4NDU0NjA"&gt;mini display port VGA adapter&lt;/a&gt; might be a useful thing to bring and unfortunately with Skills Matter being in the middle of an office move there wasn't one to hand. Luckily I was able to borrow a laptop so at least I could get my slides up on the projector.&lt;br /&gt;&lt;br /&gt;&lt;div style="width:425px;text-align:left" id="__ss_2550895"&gt;&lt;a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/rfletcher/testing-grails-applications-with-selenium-rc" title="Testing Grails Applications With Selenium Rc"&gt;Testing Grails Applications With Selenium Rc&lt;/a&gt;&lt;object style="margin:0px" width="425" height="355"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=testinggrailsapplicationswithseleniumrc-091121003233-phpapp01&amp;stripped_title=testing-grails-applications-with-selenium-rc" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=testinggrailsapplicationswithseleniumrc-091121003233-phpapp01&amp;stripped_title=testing-grails-applications-with-selenium-rc" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;"&gt;View more &lt;a style="text-decoration:underline;" href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a style="text-decoration:underline;" href="http://www.slideshare.net/rfletcher"&gt;Robert Fletcher&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-4419078667735737653?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/4419078667735737653/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=4419078667735737653' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/4419078667735737653'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/4419078667735737653'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2009/11/slides-from-ggug.html' title='Slides from GGUG'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-4923937079229224000</id><published>2009-11-05T20:58:00.001Z</published><updated>2009-11-05T21:03:31.446Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails plugins'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='selenium'/><title type='text'>Grails Selenium RC Plugin Released</title><content type='html'>I've finally got the first release of the Selenium RC plugin out of the door. Just run &lt;code&gt;grails install-plugin selenium-rc&lt;/code&gt; to install.&lt;br /&gt;&lt;br /&gt;For anyone unfamiliar with &lt;a href="http://selenium-rc.seleniumhq.org/"&gt;Selenium RC&lt;/a&gt; basically the plugin allows you to write and run Selenium tests in Groovy to functionally test Grails apps using a real browser. The tests run in the functional phase using &lt;code&gt;grails test-app&lt;/code&gt; or &lt;code&gt;grails test-app -functional&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;In terms of compatibility there is a very minor issue with Safari and some slightly more annoying ones with IE - all of which the plugin's default configuration will work around for you. Unfortunately Firefox 3.5 on OSX Snow Leopard doesn't want to play at all due to an &lt;a href="http://jira.openqa.org/browse/SRC-743"&gt;open Selenium bug&lt;/a&gt;. Firefox on other platforms, Google Chrome and Opera all appear to be 100% compatible.&lt;br /&gt;&lt;br /&gt;I've tried to make writing the tests themselves as similar to regular Grails unit and integration testing as possible. Not only that, if you have the &lt;a href="http://grails.org/plugin/spock"&gt;Spock plugin&lt;/a&gt; installed you can write your Selenium tests as Spock Specifications.&lt;br /&gt;&lt;br /&gt;Documentation is &lt;a href="http://grails.org/plugin/selenium-rc"&gt;here&lt;/a&gt;, source code is on &lt;a href="http://github.com/robfletcher/grails-selenium-rc "&gt;GitHub&lt;/a&gt; and issues and feature requests can be raised on &lt;a href="http://jira.codehaus.org/browse/GRAILSPLUGINS/component/14229 "&gt;Codehaus' JIRA&lt;/a&gt;. I've got plenty of things to work on for future releases such as Selenium Grid integration and automatic screen-grabbing when assertions fail.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-4923937079229224000?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/4923937079229224000/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=4923937079229224000' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/4923937079229224000'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/4923937079229224000'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2009/11/grails-selenium-rc-plugin-released.html' title='Grails Selenium RC Plugin Released'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-962322079657599744</id><published>2009-11-02T17:24:00.000Z</published><updated>2009-11-02T17:24:00.242Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails plugins'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='selenium'/><title type='text'>Talk on Selenium RC Testing In Grails</title><content type='html'>I'll be delivering a short talk about testing Grails apps with the &lt;a href="http://github.com/robfletcher/grails-selenium-rc"&gt;Selenium RC plugin&lt;/a&gt; I'm &lt;a href="http://adhockery.blogspot.com/2009/09/testing-grails-apps-with-selenium-rc.html"&gt;working on&lt;/a&gt; at the &lt;a href="http://skillsmatter.com/user-group/java-jee/ggug"&gt;London Groovy and Grails User Group&lt;/a&gt; on 20th November. Details are &lt;a href="http://skillsmatter.com/event/java-jee/testing-grails-applications-with-selenium-rc"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The plugin is basically release ready, I'll try to make the final push some time this week so that it's out in the wild in advance of the talk (and hopefully any particularly idiotic bugs are reported and fixed before I make a total fool of myself).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-962322079657599744?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/962322079657599744/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=962322079657599744' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/962322079657599744'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/962322079657599744'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2009/11/talk-on-selenium-rc-testing-in-grails.html' title='Talk on Selenium RC Testing In Grails'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-7881194992427544942</id><published>2009-11-02T10:48:00.000Z</published><updated>2009-11-02T10:48:10.769Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='git'/><category scheme='http://www.blogger.com/atom/ns#' term='hudson'/><category scheme='http://www.blogger.com/atom/ns#' term='ubuntu'/><title type='text'>Git and Hudson</title><content type='html'>I just encountered a rather annoying problem when running &lt;a href="http://hudson-ci.org/"&gt;Hudson&lt;/a&gt; as a service on &lt;a href="http://ubuntu.com/"&gt;Ubuntu&lt;/a&gt;. I was getting the following exception whenever the build checked code out of &lt;a href="http://github.com/"&gt;GitHub&lt;/a&gt;:&lt;pre&gt;hudson.plugins.git.GitException: Could not apply tag hudson-Selenium_RC_Plugin-23&lt;br /&gt; at hudson.plugins.git.GitAPI.tag(GitAPI.java:265)&lt;br /&gt;&lt;/pre&gt;It turns out Git needs a username to be set and the hudson user that the Debian package creates when Hudson is installed doesn't have one. Easily fixed by using &lt;code&gt;sudo nano /etc/passwd&lt;/code&gt; to add &lt;code&gt;Hudson,,,&lt;/code&gt; into the hudson user's entry (if you look at your own entry you should see where it needs to go).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-7881194992427544942?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/7881194992427544942/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=7881194992427544942' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/7881194992427544942'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/7881194992427544942'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2009/11/git-and-hudson.html' title='Git and Hudson'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-96995861206287557</id><published>2009-09-14T16:00:00.000+01:00</published><updated>2009-09-14T16:00:47.167+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails plugins'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='selenium'/><title type='text'>Testing Grails Apps With Selenium-RC</title><content type='html'>I &lt;a href="http://adhockery.blogspot.com/2009/09/thoughts-on-testing.html"&gt;mentioned in my last post&lt;/a&gt; that I'd started to think we were going about &lt;a href="http://seleniumhq.org/"&gt;Selenium&lt;/a&gt; testing all wrong. For years I've been writing Selenium tests using the &lt;a href="http://seleniumhq.org/projects/ide/"&gt;Selenium IDE&lt;/a&gt;, so the tests are in HTML files. When doing pre-commit testing and on CI the tests are run with the &lt;tt&gt;HtmlTestRunner&lt;/tt&gt;. This technique is fine and well - developing tests with the IDE is fast and they can be easily worked on an re-tested in the IDE until they are correct. However, some things have always bothered me and Adam Goucher's thoughts on &lt;a href="http://adam.goucher.ca/?p=1198"&gt;the Selenium Value Chain&lt;/a&gt; crystallised some of those suspicions.&lt;br /&gt;&lt;br /&gt;So what are the big advantages of using &lt;a href="http://seleniumhq.org/projects/remote-control/"&gt;Selenium RC&lt;/a&gt; over just the IDE and &lt;tt&gt;HtmlTestRunner&lt;/tt&gt;?&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Test design&lt;/h3&gt;Selenium tests written in HTML tend to either become an amorphous blob, not testing one simple thing or proliferate to the point of having hundreds of small test files. With Selenium RC you can write Selenium test classes with multiple test case methods just as you would unit tests. Each test case can be neat, self-contained and share set up with other test cases in the same class. Also by abstracting out common command sequences into utility methods you can start to develop a higher level DSL for testing your application. In HTML tests this can be done by writing extension functions in Javascript but it's not as straightforward.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Data fixtures&lt;/h3&gt;Data set up is the biggest headache when writing Selenium tests in HTML. You can't drop out of &lt;em&gt;selenese&lt;/em&gt; and set up a couple of domain objects so you end up either trying to run all your tests against a monolithic data fixture (a Sisyphean task if any of your tests make modifications to the data) or write some sort of URL endpoints that can set up and tear down data. We've done the latter and it's resulted in the single most bloated, horrible, misused bit of code in our app. Fixtures get re-used by other tests because they set up approximately appropriate data - until some change requires a change in the fixture and suddenly a bunch of unrelated tests fail. Selenium RC tests don't have this problem; you're in Groovy-land so you can access domain classes directly and use the invaluable &lt;a href="http://grails.org/plugin/build-test-data"&gt;build-test-data plugin&lt;/a&gt; to set data up.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Data verification&lt;/h3&gt;I mentioned previously the &lt;a href="http://adhockery.blogspot.com/2009/09/thoughts-on-testing.html#false-moniker"&gt;anti-pattern of false moniker testing&lt;/a&gt; and HTML based Selenium tests are terrible for this. If you have a test that creates some data, how do you verify it has done it correctly? The only way is to scrape the data on another screen - &lt;em&gt;e.g.&lt;/em&gt; a CRUD list or show view. Ugh! With Selenium RC you can read the data from the database with standard Grails domain classes and verify your expectations directly.&lt;br /&gt;&lt;br /&gt;I started experimenting over the weekend with getting Selenium RC tests written in Groovy to run using &lt;code&gt;grails test-app -functional&lt;/code&gt;. It turns out to be really fairly straightforward and I've &lt;a href="http://github.com/robfletcher/grails-selenium-rc"&gt;put some alpha code up on GitHub&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-96995861206287557?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/96995861206287557/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=96995861206287557' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/96995861206287557'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/96995861206287557'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2009/09/testing-grails-apps-with-selenium-rc.html' title='Testing Grails Apps With Selenium-RC'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-2306476345181328137</id><published>2009-09-11T02:56:00.004+01:00</published><updated>2009-09-14T15:52:02.859+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><title type='text'>Thoughts on Testing</title><content type='html'>&lt;p&gt;These are some of the practices I try to live by when writing test coverage. Some of the detail may be &lt;a href="http://grails.org/"&gt;Grails&lt;/a&gt;-centric since that's been my development platform of choice for the last couple of years, but the gist of the points is generally applicable.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;I've been thinking about posting something like this for quite a while and was pushed over the edge by reading some interesting things...&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.think-box.co.uk/"&gt;Simon Baker&lt;/a&gt; recommended that I read what J.B. Rainsberger &lt;a href="http://jbrains.ca/permalink/242"&gt;has to say about integration tests&lt;/a&gt; which chimed with my disgruntlement with them and my tendency to refactor old integration tests into unit tests when I touch related code.&lt;/li&gt;&lt;li&gt;&lt;a href="http://agileotter.blogspot.com/"&gt;Tim Ottinger&lt;/a&gt; posted about &lt;a href="http://agileinaflash.blogspot.com/2009/09/stopping-bad-test-death-spiral.html"&gt;stopping the 'bad test death spiral'&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;&lt;a href="http://twitter.com/franklywatson"&gt;Jerome Pimmel&lt;/a&gt; pointed me at &lt;a href="http://adam.goucher.ca/?p=1198"&gt;this article&lt;/a&gt; that adds to my growing suspicion that we're going about &lt;a href="http://seleniumhq.org/"&gt;Selenium&lt;/a&gt; testing all wrong!&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h3&gt;&lt;a name="one-logical-assertion"&gt;&lt;br /&gt;Make just one (logical) assertion per test.&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;The prime attribute of a good test case is legibility. When my change breaks your test I don't what to be scratching my head trying to figure out what it is your the test is trying to prove. The best way to achieve legibility is to have each test case test &lt;i&gt;just one thing&lt;/i&gt;. Sure, it may take more than one actual assert statement to test it properly. For example to test a query returns correct values you may want to assert that the return value is non-null, that it is a collection with the correct size and that each element of the collection complies with the query parameters. Those are separate assertion statements but in the service of a single &lt;em&gt;logical&lt;/em&gt; assertion.&lt;/p&gt;&lt;p&gt;One of the worst habits you can get into when adding new functionality is to just bung a few more asserts into an existing test case. Imagine we're testing a list action on a Grails controller class. There's an existing test case to confirm the list of instances in the model are correct. You implement a new requirement to load some sidebar content for the page by adding some new stuff to the model (leaving aside the fact that there are better ways to achieve this). This change should be tested with a separate (set of) test case(s) to those testing the list model is correct. That may mean some duplication with several test cases invoking the same controller action with the same parameters but the trade-off is that each test case is self-contained, legible and will not break due to further changes that aren't related to the functionality the test is supposed to be verifying.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;&lt;a name="test-case-names"&gt;&lt;br /&gt;Name test cases according to what they are testing&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;This sounds obvious, but how often do you come across test cases named something like &lt;tt&gt;testSaveArticle&lt;/tt&gt; that doesn't make it obvious &lt;em&gt;what&lt;/em&gt; it is testing about saving an article? A good test case name is verbose but only as verbose as it needs to be; names like &lt;tt&gt;testListReturnsEmptyListWhenNoResultsFound&lt;/tt&gt;, &lt;tt&gt;testListOnlyReturnsLiveAssets&lt;/tt&gt;, &lt;tt&gt;testUserIsRedirectedToLoginFormIfNotLoggedIn&lt;/tt&gt; tell me what I have broken when my changes cause those tests to fail. On the other hand if a test case name is too long or contains a lot of &lt;em&gt;'and's&lt;/em&gt; &amp; &lt;em&gt;'or's&lt;/em&gt; it's probably a sign that the test is doing too much and not making a single logical assertion.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;&lt;a name="helper-methods"&gt;&lt;br /&gt;Avoid obliquely named 'helper' methods&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Few things bug me more when trying to decipher other peoples' tests than helper methods whose names either don't describe properly what it is they do or that have a raft of side effects. These things make tests harder to read, not easier! Names like &lt;tt&gt;initMocks&lt;/tt&gt; (to do what?), &lt;tt&gt;createArticles&lt;/tt&gt; (how many? anything special about them? what behaviour are they trying to drive out?) or &lt;tt&gt;checkModel&lt;/tt&gt; (what about it? how reusable is this?) require the person maintaining your test cases to find the implementation and figure out what it's doing.&lt;/p&gt;&lt;p&gt;Worse, such methods have a tendency to accumulate complex parameters over time, (often with defaults designed to minimise impact on existing code at the expense of making any sense) as they get re-used in new test cases that require them to do slightly different things.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;&lt;a name="test-per-method"&gt;&lt;br /&gt;Avoid the &lt;em&gt;test-per-method&lt;/em&gt; anti-pattern&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;The 'test-per-method' anti-pattern is characterised by test cases named &lt;tt&gt;test&lt;em&gt;MethodNameX&lt;/em&gt;&lt;/tt&gt; that attempt to test all the paths through a given API method in a single test case (or worse, test only the happy path). A lot of people start out writing unit tests this way, probably because a lot of unit testing tutorials are written this way.&lt;/p&gt;&lt;p&gt;The problem is this pattern bundles a bunch of assertions into a single test and if the earlier ones fail the later ones won't even run meaning you can waste time uncovering layers of broken functionality as you work your way through the failures and re-run the test.&lt;/p&gt;&lt;p&gt;Legibility suffers as well as it may not be obvious at a glance what edge cases, boundary conditions and side-effects are covered and what the expectations for them are. If any kind of state has to be reset between different calls to a method then you will end up writing code that you simply wouldn't if you separated things out into multiple test cases.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;&lt;a name="edge-cases"&gt;&lt;br /&gt;Test edge cases and variant behaviour&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Tests that only cover the &lt;em&gt;happy path&lt;/em&gt; give you false confidence. Coverage should include things like...&lt;/p&gt;&lt;ul&gt;&lt;li&gt;What happens when &lt;tt&gt;null&lt;/tt&gt; is passed to this method?&lt;/li&gt;&lt;li&gt;What is returned when a query finds no results?&lt;/li&gt;&lt;li&gt;What happens when you can't connect to that web service or the connection times out?&lt;/li&gt;&lt;li&gt;What happens when a user submits a form with incorrect data?&lt;/li&gt;&lt;li&gt;What happens when someone figures out your URL scheme includes domain instance ids and starts crafting their own URLs to retrieve records that don't exist?&lt;/li&gt;&lt;li&gt;What happens when someone figures out your URL includes a &lt;tt&gt;maxResults&lt;/tt&gt; parameter and crafts a URL to request 10&lt;sup&gt;100&lt;/sup&gt; results?&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;TDD is your friend here; if you don't write the code until you've got a test for it, it's a lot harder to miss coverage of edge cases. Similarly the first thing you do when a bug is uncovered is to write a test that fails &lt;em&gt;then&lt;/em&gt; fix it.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;&lt;a name="false-moniker"&gt;&lt;br /&gt;Test the thing you care about not a signifier&lt;/a&gt;&lt;/h3&gt;&lt;/&gt;Max &lt;a href="http://stateyourbizness.blogspot.com/2008/07/good-unit-testing-practice.html"&gt; introduced me to the anti-pattern of false moniker testing&lt;/a&gt; and it's really changed the way I write assertions. It's an easy trap to fall into. Imagine you're testing that a query only returns 'live' records. Do you set up some &lt;em&gt;live&lt;/em&gt; and some &lt;em&gt;non-live&lt;/em&gt; records with particular names and then test that the names you expect show up in the results, or do you set up the data then assert that all the results actually are 'live' records? The former is terribly error prone (you assume you've set the data up correctly) and much less legible (which records are we expecting? Why that one in particular?)&lt;/p&gt;&lt;p&gt;Groovy's &lt;a href="http://groovy.codehaus.org/groovy-jdk/java/lang/Object.html#every()"&gt;&lt;tt&gt;every&lt;/tt&gt;&lt;/a&gt; iterator method is a godsend here enabling you to write code like:&lt;/p&gt;&lt;pre&gt;def results = MyDomain.findAllLiveRecords()&lt;br /&gt;assertFalse results.isEmpty()&lt;br /&gt;assertTrue results.every { it.state == 'live' }&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;&lt;a name="monolithic-setup"&gt;&lt;br /&gt;Avoid the monolithic setUp method&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Much as it's bad to overload individual test cases with too many assertions it quickly becomes a problem when your &lt;tt&gt;setUp&lt;/tt&gt; method is trying to set up data for too many test cases. Different test cases will probably require slightly different data to drive them which results in &lt;tt&gt;setUp&lt;/tt&gt; trying to be all things to all cases or doing things that only a subset of the test cases actually need. As new functionality is developed the &lt;tt&gt;setUp&lt;/tt&gt; becomes a black hole, accumulating more and more mass and becoming less legible and harder to refactor. The cohesion of the individual tests is harmed as well as it's hard to tell at a glance what data exists when an individual test case is run.&lt;/p&gt;&lt;p&gt;Ideally &lt;tt&gt;setUp&lt;/tt&gt; should only be used for bootstrapping things that are truly common between &lt;em&gt;all&lt;/em&gt; test cases and the test cases themselves should be responsible for setting up data to drive the test case's assertions.&lt;/p&gt;&lt;p&gt;Really bad examples of this problem will have &lt;tt&gt;setUp&lt;/tt&gt; create a bunch of data and then some of the test cases actually &lt;em&gt;delete it&lt;/em&gt; again before doing anything!&lt;br /&gt;The worst example I've ever seen was from a project I worked on where the entire integration suite used a single DBUnit fixture! It was next to impossible to figure out what data would be returned in particular scenarios, impossible to change anything in the fixture without breaking a raft of other tests and the &lt;tt&gt;setUp&lt;/tt&gt; and &lt;tt&gt;tearDown&lt;/tt&gt; phases were so slow that the integration suite took 3 1/2 hours to run!&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;&lt;a name="simple-data-fixtures"&gt;&lt;br /&gt;Keep data fixtures simple&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;On a related note it's worth striving to keep test data fixtures as simple as possible. For example, if a test has to wire up a bunch of properties and sub-graphs on domain object instances to satisfy constraints it can be really hard to see the wood for the trees when trying to figure out what data the test actually cares about.&lt;/p&gt;&lt;p&gt;When testing Grails apps the &lt;a href="http://grails.org/plugin/build-test-data"&gt;build-test-data plugin&lt;/a&gt; is a fantastic tool here. It allows sensible defaults to be configured so that tests only need to specify the properties they need to drive their assertions. With well thought out defaults in &lt;tt&gt;TestDataConfig.groovy&lt;/tt&gt; the resulting test code can be very simple.&lt;/p&gt;&lt;p&gt;In unit tests the situation is easier. Since domain objects don't need to pass constraints to simulate persistent instances via &lt;a href="http://grails.org/doc/latest/guide/9.%20Testing.html#9.1%20Unit%20Testing"&gt;mockDomain&lt;/a&gt; you don't need to jump through hoops setting properties and wiring up sub-graphs, test cases can set up simple skeleton objects that just contain sufficient state to drive the functionality and assertions the test case is making.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;&lt;a name="test-level"&gt;&lt;br /&gt;Test at the appropriate level&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Slow-running integration tests that are not testing anything that couldn't be adequately tested with unit tests are just wasting time. In the Grails pre 1.1 this was a real issue as the enhancements that Grails makes to artefacts (domain classes, controllers, etc.) were not available in unit tests and therefore integration tests were the only practical way to Grails artefacts. Now with the unit testing support found in the &lt;tt&gt;grails.test&lt;/tt&gt; package this is much less of an issue.&lt;/p&gt;&lt;p&gt;Integration tests definitely have their place but, I believe, should be used sparingly for things that a unit test &lt;em&gt;cannot&lt;/em&gt; test and not just written as a matter of course. In Grails apps, for example, &lt;a href="http://grails.org/doc/latest/guide/single.html#5.4.2%20Criteria"&gt;criteria queries&lt;/a&gt; and &lt;a href="http://grails.org/doc/latest/guide/single.html#6.5%20Web%20Flow"&gt;webflows&lt;/a&gt; cannot be tested with unit tests. I would also argue that there is value in integration testing things like complex queries or transactional behaviour where the amount of mocking required to get a unit test to work would result in you simply testing your own assumptions or expectations.&lt;/p&gt;&lt;p&gt;Do...&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Write integration tests that add coverage that unit tests cannot.&lt;/li&gt;&lt;li&gt;Learn about the Grails unit testing support and understand the differences between unit and integration tests.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Don't...&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Write an integration test when you should be writing a unit test or functional test.&lt;/li&gt;&lt;li&gt;Write integration tests that re-cover what is already adequately covered by unit tests.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;I find that integration tests classes named for a single class (&lt;em&gt;e.g.&lt;/em&gt; if I have a &lt;tt&gt;SecurityController&lt;/tt&gt; and an integration test called &lt;tt&gt;SecurityControllerTests&lt;/tt&gt;) are a bad code smell worth looking out for. They often tend to be an integration test masquerading as a unit test.&lt;/p&gt;&lt;p&gt;Refactoring Grails integration tests into unit tests doesn't (usually) take long, speeds up your build and I find often results in up to 50% less test code with the same amount of coverage.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;&lt;a name="functional-tests"&gt;&lt;br /&gt;Write functional test coverage&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Okay, so your unit test verifies that your controller's &lt;em&gt;list&lt;/em&gt; action will accept a &lt;tt&gt;sort&lt;/tt&gt; parameter and return query results appropriately but it can't test that the associated view renders a column-heading link that sends that param or that clicking on it again reverses the order. When you start developing rich functionality on a web front-end a back-end unit test isn't going to do you a lot of good either.&lt;/p&gt;&lt;p&gt;Grails' &lt;a href="http://grails.org/plugin/functional-test"&gt;functional testing plugin&lt;/a&gt; is a pretty good tool although for rich interaction testing I'd rather use &lt;a href="http://seleniumhq.org/"&gt;Selenium&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Discussion of practices for these kind of tests really justifies a whole other post.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-2306476345181328137?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/2306476345181328137/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=2306476345181328137' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/2306476345181328137'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/2306476345181328137'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2009/09/thoughts-on-testing.html' title='Thoughts on Testing'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-5995216559051089041</id><published>2009-09-07T06:04:00.005+01:00</published><updated>2009-09-07T06:26:35.300+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='webflow'/><category scheme='http://www.blogger.com/atom/ns#' term='grails plugins'/><title type='text'>Session Bound Temporary Files</title><content type='html'>I've just released &lt;a href="http://grails.org/plugin/session-temp-files"&gt;Session Temp Files&lt;/a&gt;, a very simple plugin for managing a temporary file storage space bound to the HTTP session. I'm working on something where a user uploads a file at the start of a webflow conversation, the flow then validates the file and may require the user to enter extra information before finally the file is saved and an associated record is added to the database. The uploaded files needed to be stored somewhere between the initial upload phase and the successful outcome of the flow where they will be copied in to a permanent storage space. The file is really too big to keep in memory in the flow scope. It's easy enough to create a temp file and delete it at the end of the flow (even if the user cancels out of the flow) however users can also do things like close the browser, suddenly decide to do something different and type in a new URL, etc. The webflow then gets abandoned in an intermediate state. The flow itself will be destroyed when the HTTP session ends but the temp files I created will hang around until the OS decides to sweep the temp directory.&lt;br /&gt;&lt;br /&gt;The plugin simply allows you to create a directory within the normal temp directory - &lt;tt&gt;System.properties."java.io.tmpdir"&lt;/tt&gt; - that will get deleted when the HTTP session expires. It binds two new methods on to &lt;a href="http://java.sun.com/javaee/5/docs/api/javax/servlet/http/HttpSession.html"&gt;HTTPSession&lt;/a&gt;: &lt;tt&gt;getTempDir()&lt;/tt&gt; returns the session's temp directory, creating it if it doesn't exist and &lt;tt&gt;createTempFile(prefix,suffix)&lt;/tt&gt; works like &lt;tt&gt;&lt;a href="http://java.sun.com/javase/6/docs/api/java/io/File.html#createTempFile(java.lang.String,%20java.lang.String)"&gt;File.createTempFile&lt;/a&gt;&lt;/tt&gt; except that the file is created inside the directory returned by &lt;tt&gt;getTempDir&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://github.com/robfletcher/grails-session-temp-files/"&gt;code is up on GitHub&lt;/a&gt; and the plugin is available from the &lt;a href="https://svn.codehaus.org/grails-plugins/grails-session-temp-files/"&gt;standard Grails plugin repository&lt;/a&gt; via &lt;tt&gt;grails install-plugin session-temp-files&lt;/tt&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-5995216559051089041?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/5995216559051089041/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=5995216559051089041' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/5995216559051089041'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/5995216559051089041'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2009/09/session-bound-temporary-files.html' title='Session Bound Temporary Files'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-8398089358305354940</id><published>2009-08-12T06:06:00.006+01:00</published><updated>2009-09-07T06:27:56.876+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='joda time'/><category scheme='http://www.blogger.com/atom/ns#' term='json'/><title type='text'>JSON Rendering Your Classes</title><content type='html'>&lt;p&gt;It turns out adding custom JSON renderers for your own types to Grails is really easy. Since I habitually use &lt;a href="http://joda-time.sourceforge.net/"&gt;Joda Time&lt;/a&gt; instead of the horrible &lt;code&gt;java.util.Date&lt;/code&gt; and even more horrible &lt;code&gt;java.util.Calendar&lt;/code&gt; I need to be able to render classes such as Joda's &lt;code&gt;DateTime&lt;/code&gt; as JSON so that domain objects with fields of those types will convert properly.&lt;/p&gt;&lt;p&gt;Implementing a renderer for a type is as easy as this: &lt;a href="http://gist.github.com/166335"&gt;&lt;code&gt;DateTimeMarshaller.java&lt;/code&gt;&lt;/a&gt;. After that all that's required is to register the new renderer in &lt;code&gt;BootStrap.groovy&lt;/code&gt; or some other appropriate spot with:&lt;/p&gt;&lt;pre&gt;grails.converters.JSON.registerObjectMarshaller new DateTimeMarshaller()&lt;/pre&gt;&lt;p&gt;I'll be adding this to the next release of the &lt;a href="http://grails.org/plugin/joda-time"&gt;Joda Time Plugin&lt;/a&gt; so that it's completely transparent.&lt;/p&gt;&lt;p&gt;&lt;em&gt;&lt;strong&gt;Update:&lt;/strong&gt;&lt;/em&gt; Actually it's even easier than I thought. This being Groovy you can just use closures like so:&lt;/p&gt;&lt;pre&gt;JSON.registerObjectMarshaller(DateTime) {&lt;br /&gt;    return it?.toString("yyyy-MM-dd'T'HH:mm:ss'Z'")&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;&lt;em&gt;&lt;strong&gt;Update:&lt;/strong&gt;&lt;/em&gt; This is now built in to version 0.5 of the &lt;a href="http://grails.org/plugin/joda-time"&gt;Joda Time Plugin&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-8398089358305354940?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/8398089358305354940/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=8398089358305354940' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/8398089358305354940'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/8398089358305354940'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2009/08/json-rendering-your-classes.html' title='JSON Rendering Your Classes'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-521354316795867925</id><published>2009-07-10T09:02:00.001+01:00</published><updated>2009-09-07T06:28:51.238+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='grails upgrade'/><category scheme='http://www.blogger.com/atom/ns#' term='events'/><category scheme='http://www.blogger.com/atom/ns#' term='acegi'/><title type='text'>Auditing data with the Acegi plugin and Grails upgrade pain</title><content type='html'>&lt;p&gt;I'm in the middle of trying to upgrade our app (again). We're running on Grails 1.1 now and I'm attempting to get us to 1.1.1 and from there to 1.2-M1. As Marc Palmer &lt;a href="http://www.anyware.co.uk/2005/2009/07/03/grails-12m1-and-why-you-need-to-download-it-now/"&gt;points out&lt;/a&gt; the more people using it the more likely it is that 1.2 final will be rock solid.&lt;/p&gt;&lt;p&gt;The problem that's biting us right now is &lt;a href="http://jira.codehaus.org/browse/GRAILS-4453"&gt;GRAILS-4453&lt;/a&gt; (or, more accurately, &lt;a href="http://opensource.atlassian.com/projects/hibernate/browse/HHH-2763"&gt;HHH-2763&lt;/a&gt;). We're using &lt;a href="http://grails.org/doc/1.1.x/guide/5.%20Object%20Relational%20Mapping%20(GORM).html#5.5.1%20Events%20and%20Auto%20Timestamping"&gt;Grails' Hibernate events support&lt;/a&gt; to track the user that created and last updated assets in our system. This isn't just us being anal, the site editors frequently search the data using those criteria so it's an essential feature.&lt;/p&gt;&lt;p&gt;In Grails 1.1 this is simplicity itself. The following code goes in the domain class and that's all there is to it:&lt;/p&gt;&lt;pre&gt; User createdBy&lt;br /&gt; User updatedBy&lt;br /&gt;&lt;br /&gt; def authenticateService&lt;br /&gt;&lt;br /&gt; def beforeInsert = {&lt;br /&gt;  createdBy = authenticateService.userDomain()&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; def beforeUpdate = {&lt;br /&gt;  updatedBy = authenticateService.userDomain()&lt;br /&gt; }&lt;/pre&gt;&lt;p&gt;Yes, it is quite 'exciting' that you're able to inject a service into a domain class instance. GORM only maps explicitly typed properties to the database so anything declared using &lt;code&gt;def&lt;/code&gt; is effectively transient.&lt;/p&gt;&lt;p&gt;Unfortunately Grails 1.1.1 includes a newer version of Hibernate that introduces a particularly horrible problem. When saving any update to our domain object now we're faced with the error: &lt;code&gt;collection [User.authorities] was not processed by flush()&lt;/code&gt;. The problem appears to be that the &lt;code&gt;User&lt;/code&gt; instance attached to &lt;code&gt;createdBy&lt;/code&gt; cannot be flushed when the &lt;code&gt;beforeUpdate&lt;/code&gt; closure executes because it has a lazy-loaded collection of authorities. Even declaring the authorities collection as &lt;code&gt;lazy: false&lt;/code&gt; doesn't help as the relationship is a bi-directional many-to-many - each &lt;code&gt;Authority&lt;/code&gt; also has a collection of all the &lt;code&gt;User&lt;/code&gt;s who have been granted that role. Given that for the purposes of displaying data to the audience of our site this audit data doesn't matter a damn I really don't want to be eager fetching it. Also, given the nature of the User-Authority relationship, casual eager fetching could result in rather a lot of data being loaded in to memory (the &lt;code&gt;User&lt;/code&gt;, his roles, all the other users with that role, all &lt;em&gt;their&lt;/em&gt; roles...)&lt;/p&gt;&lt;p&gt;Our options seem to be:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Explicitly eager fetch the &lt;code&gt;User&lt;/code&gt; data in places where the owning object will get updated. Since the domain class in question is the root of a heirarchy of 13 sub-classes (things this project has taught me #63: never do this) and varieties get updated by a service or two, at least one controller and one Quartz and several hundred Selenium test fixtures, it's going to be a massive PITA and just as bad to remove if/when HHH-2763 ever gets fixed.&lt;/li&gt;&lt;li&gt;Break referential integrity and store username or id rather than an actual domain object relationship. This feels horribly wrong and is likely to cause problems down the line.&lt;/li&gt;&lt;li&gt;Store the created/updated information as a domain object of its own. This would make the query to find data by who created or updated it more complex (although not impossibly so) and might actually be prone to the same original bug&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;I don't know if anyone might have come across this problem and has some kind of workaround (preferably one that isn't an evil hack). I'd really appreciate any pointers.&lt;/p&gt;&lt;p&gt;&lt;em&gt;&lt;strong&gt;Update:&lt;/strong&gt;&lt;/em&gt; This is fixed in Grails 1.2-M2&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-521354316795867925?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/521354316795867925/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=521354316795867925' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/521354316795867925'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/521354316795867925'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2009/07/auditing-data-with-acegi-plugin-and.html' title='Auditing data with the Acegi plugin and Grails upgrade pain'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-2474812452969130287</id><published>2009-06-23T18:17:00.002+01:00</published><updated>2009-06-23T18:54:44.460+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails plugins'/><category scheme='http://www.blogger.com/atom/ns#' term='grails scripts'/><category scheme='http://www.blogger.com/atom/ns#' term='ivy'/><title type='text'>Scripting Plugin and Dependency Installation</title><content type='html'>&lt;/p&gt;Another quick script that I find quite useful, particularly on continuous integration servers is my &lt;a href="http://gist.github.com/134689"&gt;Prepare.groovy&lt;/a&gt; script. It solves a couple of problems&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Some plugins are not as well behaved as others on installation, for example &lt;a href="http://grails.org/plugin/functional-test"&gt;the Functional Testing plugin&lt;/a&gt; automatically installs when &lt;code&gt;test-app&lt;/code&gt; or &lt;code&gt;run-app&lt;/code&gt; is installed but will then immediately crash with a &lt;code&gt;ClassNotFoundException&lt;/code&gt; 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.&lt;/li&gt;&lt;li&gt;&lt;a href="http://grails.org/plugin/ivy"&gt;The Ivy plugin&lt;/a&gt; is great but &lt;code&gt;test-app&lt;/code&gt; and &lt;code&gt;run-app&lt;/code&gt; won't invoke its &lt;code&gt;get-dependencies&lt;/code&gt; target to pull down libraries the way they will automatically install plugins.&lt;/li&gt;&lt;li&gt;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.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The script simply ensures all plugins are installed and then invokes the Ivy plugin's &lt;code&gt;get-dependencies&lt;/code&gt; 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.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-2474812452969130287?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/2474812452969130287/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=2474812452969130287' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/2474812452969130287'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/2474812452969130287'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2009/06/scripting-plugin-and-dependency.html' title='Scripting Plugin and Dependency Installation'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-4240357558215415366</id><published>2009-06-18T05:54:00.004+01:00</published><updated>2009-06-18T06:26:28.895+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gorm'/><category scheme='http://www.blogger.com/atom/ns#' term='joda time'/><title type='text'>Joda Time Auto-Timestamping Issue on Grails 1.1.1</title><content type='html'>&lt;p&gt;I've not upgraded most of my code to Grails 1.1.1 yet so I hadn't noticed this problem until it was &lt;a href="http://www.nabble.com/Problem-with-Joda-plugin-and-autotimestamping-td24068191.html#a24068191"&gt;brought to my attention&lt;/a&gt; by Manuel Vio on the &lt;a href="http://grails.org/Mailing+lists"&gt;grails-user&lt;/a&gt; mailing list.&lt;/p&gt;&lt;p&gt;I &lt;a href="http://jira.codehaus.org/browse/GRAILS-4689"&gt;raised a bug&lt;/a&gt; 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 &lt;a href="http://grails.org/plugin/joda-time"&gt;Joda Time plugin&lt;/a&gt; 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 &lt;em&gt;id&lt;/em&gt; property. However, on Grails 1.1.1 the bug is causing a nasty failure on auto-timestamping.&lt;/p&gt;&lt;p&gt;Under Grails 1.1 you can use a Joda &lt;em&gt;DateTime&lt;/em&gt; for an auto-timestamped fields:&lt;/p&gt;&lt;pre&gt;DateTime dateCreated&lt;br /&gt;DateTime lastUpdated&lt;br /&gt;&lt;br /&gt;static mapping = {&lt;br /&gt;    dateCreated type: PersistentDateTime&lt;br /&gt;    lastUpdated type: PersistentDateTime&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;These behave exactly like the regular &lt;em&gt;Date&lt;/em&gt; fields with those names, i.e. they're &lt;a href="http://grails.org/doc/1.1/guide/single.html#5.5.1%20Events%20and%20Auto%20Timestamping"&gt;set automatically on save and update&lt;/a&gt;. In Grails 1.1.1 the same class will fail on save with a &lt;em&gt;GroovyRuntimeException&lt;/em&gt; &lt;code&gt;Could not find matching constructor for: java.lang.Object(java.lang.Long)&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;There is a (somewhat strange) workaround - declare the timestamped fields as non-lazy!&lt;/p&gt;&lt;pre&gt;DateTime dateCreated&lt;br /&gt;DateTime lastUpdated&lt;br /&gt;&lt;br /&gt;static mapping = {&lt;br /&gt;    dateCreated type: PersistentDateTime, lazy: false&lt;br /&gt;    lastUpdated type: PersistentDateTime, lazy: false&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;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 &lt;em&gt;are&lt;/em&gt; associations, this happens to them. The auto-timestamping code initialises the properties using &lt;code&gt;property.getType().newInstance(System.currentTimeMillis())&lt;/code&gt;. Unfortunately, because &lt;em&gt;property&lt;/em&gt; is actually the lazy-load proxy rather than the real property &lt;code&gt;property.getType()&lt;/code&gt; returns &lt;em&gt;Object&lt;/em&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-4240357558215415366?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/4240357558215415366/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=4240357558215415366' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/4240357558215415366'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/4240357558215415366'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2009/06/joda-time-auto-timestamping-issue-on.html' title='Joda Time Auto-Timestamping Issue on Grails 1.1.1'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-420419119332494813</id><published>2009-06-15T11:24:00.003+01:00</published><updated>2009-06-15T13:11:07.788+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails plugins'/><category scheme='http://www.blogger.com/atom/ns#' term='grails scripts'/><title type='text'>Checking for plugin updates</title><content type='html'>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 &lt;code&gt;grails list-plugins&lt;/code&gt; 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 &lt;a href="http://gist.github.com/130031"&gt;this script&lt;/a&gt; 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.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-420419119332494813?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/420419119332494813/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=420419119332494813' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/420419119332494813'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/420419119332494813'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2009/06/checking-for-plugin-updates.html' title='Checking for plugin updates'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-7834974213648150426</id><published>2009-06-13T06:25:00.007+01:00</published><updated>2009-06-15T13:18:04.592+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='gorm'/><category scheme='http://www.blogger.com/atom/ns#' term='criteria queries'/><title type='text'>Querying by Association Redux</title><content type='html'>&lt;p&gt;A couple of months back I &lt;a href="http://adhockery.blogspot.com/2009/04/associations-and-criteria-queries.html"&gt;posted&lt;/a&gt; about the problems with criteria queries where you want results with a collection property that &lt;em&gt;contains&lt;/em&gt; some value.&lt;/p&gt;&lt;p&gt;Last night I was reading through my new copy of &lt;a href="http://blogs.bytecode.com.au/glen/"&gt;Glen Smith&lt;/a&gt; and Peter Ledbrook's &lt;a href="http://www.amazon.co.uk/Grails-Action-Glen-Smith/dp/1933988932"&gt;Grails In Action&lt;/a&gt; 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.&lt;/p&gt;&lt;p&gt;To recap. If I have these domain classes:&lt;/p&gt;&lt;pre&gt;class Pirate {&lt;br /&gt;    String name&lt;br /&gt;    static belongsTo = Ship&lt;br /&gt;    static hasMany = [ships: Ship]&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class Ship {&lt;br /&gt;    String name&lt;br /&gt;    static hasMany = [crew: Pirate]&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;and I want to query for all the &lt;em&gt;Ships&lt;/em&gt; containing a particular &lt;em&gt;Pirate&lt;/em&gt; I would probably try to do this:&lt;/p&gt;&lt;pre&gt;def ships = Ship.withCriteria {&lt;br /&gt;    crew {&lt;br /&gt;        eq("name", "Blackbeard")&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;Unfortunately, while I end up with the correct &lt;em&gt;Ship&lt;/em&gt; instances, each of their &lt;em&gt;crew&lt;/em&gt; collections only contains the item(s) that matched the criteria regardless of any others that may actually exist.&lt;/p&gt;&lt;p&gt;Using an alias we &lt;em&gt;can&lt;/em&gt; do this type of query without resorting to HQL:&lt;/p&gt;&lt;pre&gt;def ships = Ship.withCriteria {&lt;br /&gt;    createAlias("crew", "c")&lt;br /&gt;    eq("c.name", "Blackbeard")&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;A complete test case that proves the point using the domain classes above is:&lt;/p&gt;&lt;pre&gt;class PirateTests extends GroovyTestCase {&lt;br /&gt;&lt;br /&gt;    void setUp() {&lt;br /&gt;        Ship.withSession {session -&gt;&lt;br /&gt;            def blackbeard = new Pirate(name: "Blackbeard")&lt;br /&gt;            def jack = new Pirate(name: "Calico Jack")&lt;br /&gt;            def bart = new Pirate(name: "Black Bart")&lt;br /&gt;            [blackbeard, jack, bart]*.save()&lt;br /&gt;&lt;br /&gt;            def ship1 = new Ship(name: "Queen Anne's Revenge")&lt;br /&gt;            ship1.addToCrew blackbeard&lt;br /&gt;            ship1.addToCrew jack&lt;br /&gt;&lt;br /&gt;            def ship2 = new Ship(name: "Royal Fortune")&lt;br /&gt;            ship2.addToCrew blackbeard&lt;br /&gt;            ship2.addToCrew bart&lt;br /&gt;&lt;br /&gt;            def ship3 = new Ship(name: "The Treasure")&lt;br /&gt;            ship3.addToCrew jack&lt;br /&gt;            ship3.addToCrew bart&lt;br /&gt;&lt;br /&gt;            [ship1, ship2, ship3]*.save()&lt;br /&gt;&lt;br /&gt;            session.flush()&lt;br /&gt;            session.clear()&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    void testQueryByAssoc() {&lt;br /&gt;        def ships = Ship.withCriteria {&lt;br /&gt;            crew {&lt;br /&gt;                eq("name", "Blackbeard")&lt;br /&gt;            }&lt;br /&gt;            order("name", "asc")&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        assertEquals 2, ships.size()&lt;br /&gt;        assertEquals "Queen Anne's Revenge, Royal Fortune", ships.name.join(", ")&lt;br /&gt;        assertEquals "Expected 2 crew but found ${ships[0].crew.name}", 2, ships[0].crew.size()&lt;br /&gt;        assertEquals "Expected 2 crew but found ${ships[1].crew.name}", 2, ships[1].crew.size()&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    void testQueryByAssocUsingAlias() {&lt;br /&gt;        def ships = Ship.withCriteria {&lt;br /&gt;            createAlias("crew", "c")&lt;br /&gt;            eq("c.name", "Blackbeard")&lt;br /&gt;            order("name", "asc")&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        assertEquals 2, ships.size()&lt;br /&gt;        assertEquals "Queen Anne's Revenge, Royal Fortune", ships.name.join(", ")&lt;br /&gt;        assertEquals "Expected 2 crew but found ${ships[0].crew.name}", 2, ships[0].crew.size()&lt;br /&gt;        assertEquals "Expected 2 crew but found ${ships[1].crew.name}", 2, ships[1].crew.size()&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;The first test fails as each &lt;em&gt;Ship&lt;/em&gt; 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.&lt;/p&gt;&lt;p&gt;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:&lt;/p&gt;&lt;pre&gt;select * from ship&lt;br /&gt;left outer join ship_crew on ship.id = ship_crew.ship_id&lt;br /&gt;left outer join pirate on ship_crew.pirate_id = pirate.id&lt;br /&gt;where pirate.name = ?&lt;br /&gt;order by ship.name asc&lt;/pre&gt;&lt;p&gt;The second (correct) query is:&lt;/p&gt;&lt;pre&gt;select * from ship&lt;br /&gt;inner join ship_crew on ship.id = ship_crew.ship_id&lt;br /&gt;inner join pirate on ship_crew.pirate_id = pirate.id&lt;br /&gt;where pirate.name = ?&lt;br /&gt;order by ship.name asc&lt;/pre&gt;&lt;p&gt;So the first query is using left outer joins and the second is using inner joins. Running those queries directly in &lt;a href="http://squirrel-sql.sourceforge.net/"&gt;SQuirreL&lt;/a&gt; returns basically the same result set so the discrepancy must be in how Hibernate treats the results. It seems Hibernate has populated the &lt;em&gt;Ship&lt;/em&gt; instance &lt;em&gt;and&lt;/em&gt; its &lt;em&gt;crew&lt;/em&gt; 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 &lt;em&gt;Ship&lt;/em&gt; instance from the query results and is treating the collection property as uninitialized.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-7834974213648150426?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/7834974213648150426/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=7834974213648150426' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/7834974213648150426'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/7834974213648150426'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2009/06/querying-by-association-redux.html' title='Querying by Association Redux'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-3860396560445910887</id><published>2009-06-13T05:51:00.005+01:00</published><updated>2009-06-14T10:01:29.466+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scaffolding'/><category scheme='http://www.blogger.com/atom/ns#' term='css'/><title type='text'>Hacking on Grails scaffolding templates</title><content type='html'>&lt;p&gt;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 &lt;em&gt;some&lt;/em&gt; 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.&lt;/p&gt;&lt;p&gt;I'd done some customising of scaffolding templates before for the &lt;a href="http://grails.org/plugin/joda-time"&gt;Joda Time plugin&lt;/a&gt; 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:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Mark up create and edit forms without using tables&lt;/li&gt;&lt;li&gt;Provide automatic indication of mandatory fields&lt;/li&gt;&lt;/ol&gt;&lt;img style="float: left;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 320px; height: 214px;" src="http://4.bp.blogspot.com/_fh9xwLFYBUw/SjMixEDGEpI/AAAAAAAACVg/wcr4gaTX2zc/s320/createpirate.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5346655408914567826" /&gt;&lt;p&gt;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 &lt;a href="http://www.virtualbox.org/"&gt;VirtualBox&lt;/a&gt; instances I use for cross-browser testing.&lt;/p&gt;&lt;h5 style="clear: both"&gt;Forms Without Tables&lt;/h5&gt;&lt;p&gt;Each form element is simply:&lt;/p&gt;&lt;pre&gt;&amp;lt;div class="prop"&amp;gt;&lt;br /&gt;    &amp;lt;label for="${p.name}"&amp;gt;Property Name&amp;lt;/label&amp;gt;&lt;br /&gt;    ${renderEditor(p)}&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;/pre&gt;&lt;p&gt;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 &lt;a href="http://www.codecouch.com/author/jeff/"&gt;Jeff&lt;/a&gt; I was able to achieve that with a lot less browser-specific tweaking than I would have thought would be necessary.&lt;/p&gt;&lt;p&gt;The necessary CSS is just:&lt;/p&gt;&lt;pre&gt;.prop {&lt;br /&gt;    margin: 1em 0;&lt;br /&gt;}&lt;br /&gt;label {&lt;br /&gt;    display: inline-block;&lt;br /&gt;    margin-right: 1.5em;&lt;br /&gt;    text-align: right;&lt;br /&gt;    width: 8em;&lt;br /&gt;}&lt;br /&gt;input, select {&lt;br /&gt;    vertical-align: middle;&lt;br /&gt;}&lt;br /&gt;textarea {&lt;br /&gt;    vertical-align: top;&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;Making the label &lt;code&gt;inline-block&lt;/code&gt; 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 &lt;code&gt;vertical-align&lt;/code&gt; 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.&lt;/p&gt;&lt;h5&gt;Automatically Indicating Mandatory Fields&lt;/h5&gt;&lt;p&gt;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 &lt;a href="http://grails.org/doc/1.1.x/api/org/codehaus/groovy/grails/validation/ConstrainedProperty.html"&gt;constrained properties&lt;/a&gt; of the domain class to determine whether to display a form field for each property. It's a very small step to use the &lt;em&gt;isNullable()&lt;/em&gt; and in the case of String properties &lt;em&gt;isBlank()&lt;/em&gt; methods to decide whether to render a mandatory indicator.&lt;/p&gt;&lt;p&gt;I simply output a span with an asterisk inside the label then styled it with:&lt;/p&gt;&lt;pre&gt;label {&lt;br /&gt;    /* other label properties as above */&lt;br /&gt;    position: relative;&lt;br /&gt;}&lt;br /&gt;label .mandatory {&lt;br /&gt;    color: #c00;&lt;br /&gt;    position: absolute;&lt;br /&gt;    right: -1.25em;&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;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 &lt;code&gt;right: -1.25em&lt;/code&gt; 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.&lt;/p&gt;&lt;p&gt;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 &lt;em&gt;quite&lt;/em&gt; 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.&lt;/p&gt;&lt;h5&gt;Source Code&lt;/h5&gt;&lt;p&gt;Here's the source code. Any suggestions for improvements would be very welcome. I based the templates on &lt;a href="http://marceloverdijk.blogspot.com/"&gt;Marcel Overdijk&lt;/a&gt;'s excellent &lt;a href="http://grails.org/plugin/i18n-templates"&gt;i18n-templates&lt;/a&gt;, the only differences are in the rendering of the form fields and the surrounding &lt;em&gt;fieldset&lt;/em&gt;.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://snipt.org/kTp"&gt;web-app/css/forms.css&lt;/a&gt; (needs to be added to grails-app/views/layouts/main.gsp)&lt;/li&gt;&lt;li&gt;&lt;a href="http://snipt.org/kUj"&gt;src/templates/scaffolding/create.gsp&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://snipt.org/kUm"&gt;src/templates/scaffolding/edit.gsp&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Something this exercise has driven home for me is that when it comes to cross-browser styling less is definitely more. Taking away &lt;em&gt;everything&lt;/em&gt;, &lt;a href="http://www.codecouch.com/2007/04/how-to-get-consistent-font-sizes-across-all-browsers/"&gt;setting the font size consistently cross-browser&lt;/a&gt;, then gradually building up with the simplest markup and styling possible yields the best results.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-3860396560445910887?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/3860396560445910887/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=3860396560445910887' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/3860396560445910887'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/3860396560445910887'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2009/06/hacking-on-grails-scaffolding-templates.html' title='Hacking on Grails scaffolding templates'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_fh9xwLFYBUw/SjMixEDGEpI/AAAAAAAACVg/wcr4gaTX2zc/s72-c/createpirate.png' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-8213328569296695054</id><published>2009-05-15T14:58:00.004+01:00</published><updated>2009-05-16T20:43:58.753+01:00</updated><title type='text'>Faster, Pussycat! Kill! Kill!</title><content type='html'>I mentioned previously that we'd seen some speed improvements in our page load time after upgrading to Grails 1.1. It turns out that for the week 3rd May to 10th May &lt;a href="http://showbiz.sky.com/"&gt;Sky Showbiz&lt;/a&gt; ranked 8th in the UK for page response time in the &lt;a href="http://www.gomez.com/"&gt;Gomez&lt;/a&gt; Benchmark Report with an average of 1.84 seconds. We came in ahead of some heavyweights like Amazon, HSBC, British Airways, etc. Sure, we weren't even close to Google (0.35 seconds!) and we rely on heavy caching for most of our responsiveness, but it's not bad for a site that's basically 8 virtual nodes (6 web and 2 DB) running a Grails app on Jetty and PostgreSQL.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-8213328569296695054?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/8213328569296695054/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=8213328569296695054' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/8213328569296695054'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/8213328569296695054'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2009/05/faster-pussycat-kill-kill.html' title='Faster, Pussycat! Kill! Kill!'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-7533631595136443481</id><published>2009-04-28T14:55:00.023+01:00</published><updated>2009-05-08T15:42:18.306+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='grails plugins'/><category scheme='http://www.blogger.com/atom/ns#' term='grails upgrade'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><title type='text'>Grails Upgrade</title><content type='html'>&lt;p&gt;We've just finished upgrading our sites to &lt;a href="http://www.grails.org/1.1+Release+Notes"&gt;Grails 1.1&lt;/a&gt; and I thought it would be worth sharing some of the &lt;a href="http://omfg.biz/"&gt;fun&lt;/a&gt; we had with the process.&lt;/p&gt;&lt;p&gt;First and foremost was a call site caching bug in Groovy 1.6.0 that caused chaos with our unit and integration tests. Basically any time we mocked a class then demanded behaviour on a static method or any time we used the metaClass to override a static method (among other things that's pretty much any unit test that goes anywhere near a domain class) the behaviour wouldn't get torn down again. This caused symptoms such as stubbed dynamic finders leaking from unit tests and breaking integration tests that would pass when re-run in isolation. We got as far as refactoring a whole bunch of test code that mocked static methods before &lt;a href="http://burtbeckwith.com/blog/"&gt;Burt Beckwith&lt;/a&gt; &lt;a href="http://jira.codehaus.org/browse/GRAILS-4448"&gt;pointed out to me&lt;/a&gt; that simply replacing $GRAILS_HOME/lib/groovy-all-1.6.0.jar with the newer version from the Groovy 1.6.1 or 1.6.2 release would fix the problem.&lt;/p&gt;&lt;p&gt;Unfortunately the same bug has another effect that was quite catastrophic for us. Any Hibernate proxy of an instance of a domain class involved in an inheritance hierarchy will throw &lt;em&gt;ClassCastException&lt;/em&gt; when you try to access a subclass property or do an &lt;em&gt;instanceof&lt;/em&gt; check. I &lt;a href="http://adhockery.blogspot.com/2009/04/when-is-pirate-not-pirate-when-its.html"&gt;blogged already&lt;/a&gt; about the &lt;em&gt;instanceof&lt;/em&gt; issue but it's actually wider ranging than I realised at the time. It can cause very unpredictable behaviour because complex relationships between objects and the way they are loaded by a controller before a page is rendered can cause this error to pop up under obscure conditions that are very hard to nail down with test coverage. To solve the problem we've had to use eager fetching in places where associations are typed as the base class of an inheritance hierarchy and to use explicit checks for proxies such as:&lt;p&gt;&lt;pre&gt;if (o instanceof HibernateProxy) {&lt;br /&gt;    o = GrailsHibernateUtil.unwrapProxy(o)&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;Hopefully this bug will be fixed in Grails 1.1.1 and we will be able to use the default lazy loading behaviour in all relationships.&lt;/p&gt;&lt;p&gt;Other problems we encountered included:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The &lt;code&gt;onLoad&lt;/code&gt; Hibernate event handler on domain classes now seems to run at a slightly different time in the object life cycle: &lt;em&gt;before&lt;/em&gt; any eager fetched collections are loaded. We had one domain class that was doing some initialisation (calculating the percentage of votes each answer to a poll had received and storing it in a transient property) that no longer worked as the persistent collection it was trying to iterate over was always empty. This was simple to refactor out and in fairness was pretty horrible anyway.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;code&gt;Config.groovy&lt;/code&gt; and related external config files are no longer loaded when running unit tests so any unit test that excercises code doing &lt;code&gt;ConfigurationHolder.config.some.value.or.other&lt;/code&gt; blew up. We solved this by simply adding the following to &lt;code&gt;_Events.groovy&lt;/code&gt; to load up config prior to the unit tests running:&lt;pre&gt;eventTestPhaseStart = { phase -&gt;&lt;br /&gt;    if (phase == 'unit') {&lt;br /&gt;        ConfigSlurper slurper = new ConfigSlurper(GrailsUtil.environment)&lt;br /&gt;        def configClass = getClass().classLoader.loadClass("Config")&lt;br /&gt;        def config = slurper.parse(configClass)&lt;br /&gt;        ConfigurationHelper.initConfig config // this step loads the external environment config file(s)&lt;br /&gt;        ConfigurationHolder.config = config&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Logger configuration has completely changed (for the better) in Grails 1.1&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Some of our tests were explicitly setting the level of particular loggers to 'OFF' because the test is deliberately causing an error condition and we didn't want the console polluted with a huge stack trace. This no longer works as the &lt;a href="http://www.bileblog.org/2003/08/the-evils-of-commons-loggingjar-and-its-ilk/"&gt;logging abstraction&lt;/a&gt; has changed to &lt;a href="http://www.slf4j.org/"&gt;SLF4J&lt;/a&gt; which does not allow you to directly set the level on &lt;a href="http://www.slf4j.org/apidocs/org/slf4j/Logger.html"&gt;its Logger class&lt;/a&gt;. Having better things to do than unwrapping logging abstractions I just turned logging off altogether in the test Grails environment.&lt;pre&gt;log4j = {&lt;br /&gt;    root {&lt;br /&gt;        off()&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;It looks like binding errors don't get reported on nullable properties when using &lt;code&gt;DomainClass.properties = params&lt;/code&gt; in a controller. I've &lt;a href="http://jira.codehaus.org/browse/GRAILS-4485"&gt;raised a bug&lt;/a&gt;.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;There's been a minor change to the &amp;lt;g:select&amp;gt; tag. Previously the &lt;em&gt;disabled&lt;/em&gt; attribute followed the HTML convention (&lt;code&gt;disabled="disabled"&lt;/code&gt;) but now the attribute value needs to be a boolean. I guess this actually makes more sense than the goofy HTML convention but I really expect most of the attributes on those sorts of tags to be pure pass-through.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;The mockDomain method used by unit tests seems to be a little inconsistent when dealing with inheritance heirarchies. If you do &lt;code&gt;mockDomain(BaseClass)&lt;/code&gt; then try to use &lt;code&gt;subClassInstance.subClassProperty&lt;/code&gt; it fails with a MissingPropertyException. I've &lt;a href="http://jira.codehaus.org/browse/GRAILS-4495"&gt;raised a bug&lt;/a&gt;.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;We had customised &lt;code&gt;Package.groovy&lt;/code&gt; to deploy our app at the root context. It seems this is now directly supported as an option in Grails 1.1 by setting &lt;code&gt;grails.app.context = '/'&lt;/code&gt; in &lt;code&gt;Config.groovy&lt;/code&gt;. I think this option was already available in Grails 1.0.3 but our patch pre-dated us upgrading to 1.0.3. One of the things I was trying to achieve while upgrading was to ensure we were patching Grails and any plugins as little as possible.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;I'd upgraded our selenium plugin (not the one in &lt;a href="http://plugins.grails.org/"&gt;the Grails plugin repository&lt;/a&gt;) a while back to cope with Grails 1.1 and upgraded the selenium server it contained at the same time. It turns out the new selenium server will time out attempting to click any anchor that uses the &lt;code&gt;javascript:&lt;/code&gt; protocol in its href. Luckily this was only being done in 2 places in our app and was easily fixed by using href="#" instead.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;One other thing we decided to do was to replace our existing suite of &lt;a href="http://grails.org/Functional+Testing"&gt;webtests&lt;/a&gt; with &lt;a href="http://www.grails.org/Grails%20Functional%20Testing"&gt;functional tests&lt;/a&gt;. Webtest has never been popular with the developers on our team and we had made a number of modifications to version 0.4 of the plugin in order to support issues like config loading and running the app at the context root of the server. These modifications caused some headaches when trying to upgrade the plugin so we decided to drop it and port the tests over to the functional test plugin. Generally I'd still rather be writing Selenium tests than using either webtest or functional tests but the functional test syntax is a little nicer and less "pseudo-XML" than webtest's.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-7533631595136443481?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/7533631595136443481/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=7533631595136443481' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/7533631595136443481'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/7533631595136443481'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2009/04/grails-upgrade.html' title='Grails Upgrade'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-3233326011054996064</id><published>2009-04-15T02:49:00.004+01:00</published><updated>2009-04-15T03:08:40.071+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='gorm'/><title type='text'>When is a Pirate not a Pirate? When it's a HibernateProxy</title><content type='html'>&lt;p&gt;At work we're in the middle of upgrading &lt;a href="http://showbiz.sky.com/"&gt;the&lt;/a&gt; &lt;a href="http://tv.sky.com/"&gt;Sky&lt;/a&gt; &lt;a href="http://movies.sky.com/"&gt;Entertainment&lt;/a&gt; &lt;a href="http://sky1.sky.com/"&gt;sites&lt;/a&gt; from Grails 1.0.3 to Grails 1.1 - a long blog post will follow with a tale of our woes! One of the changes in Grails 1.1 is that one-to-one domain associations are now lazy by default. This raised an interesting problem for us as it meant we were now sometimes dealing with &lt;a href="http://www.hibernate.org/hib_docs/v3/api/org/hibernate/proxy/HibernateProxy.html"&gt;HibernateProxy&lt;/a&gt; instances where before we weren't.&lt;/p&gt;&lt;p&gt;For example, let's imagine we have a &lt;em&gt;Pet&lt;/em&gt; domain class that is has an owner that is a &lt;em&gt;Person&lt;/em&gt; and there exists another domain class, &lt;em&gt;Pirate&lt;/em&gt; that is a specialisation of &lt;em&gt;Person&lt;/em&gt;:&lt;/p&gt;&lt;h4&gt;Pet.groovy&lt;/h4&gt;&lt;pre&gt;class Pet {&lt;br /&gt;    String type&lt;br /&gt;    String name&lt;br /&gt;    Person owner&lt;br /&gt;}&lt;/pre&gt;&lt;h4 style="margin-top: 1em;"&gt;Person.groovy&lt;/h4&gt;&lt;pre&gt;class Person {&lt;br /&gt;&lt;br /&gt;    String name&lt;br /&gt;&lt;br /&gt;    boolean equals(Object o) {&lt;br /&gt;        if (this.is(o)) return true&lt;br /&gt;        if (o == null) return false&lt;br /&gt;        if (!(o instanceof Person)) return false&lt;br /&gt;        return name == o.name&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    // hashCode and toString ommitted&lt;br /&gt;}&lt;/pre&gt;&lt;h4 style="margin-top: 1em;"&gt;Pirate.groovy&lt;/h4&gt;&lt;pre&gt;class Pirate extends Person {&lt;br /&gt;&lt;br /&gt;    String nickname&lt;br /&gt;&lt;br /&gt;    boolean equals(Object o) {&lt;br /&gt;        if (!super.equals(o)) return false&lt;br /&gt;        if (!(o instanceof Pirate)) return false&lt;br /&gt;        return nickname == o.nickname&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // hashCode and toString ommitted&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;We want to test that either a regular &lt;em&gt;Person&lt;/em&gt; or a &lt;em&gt;Pirate&lt;/em&gt; can own a &lt;em&gt;Pet&lt;/em&gt;. To do so we write an integration test like this:&lt;/p&gt;&lt;pre&gt;void testAssignPersonAsPetOwner() {&lt;br /&gt;    Person terry = new Person(name: 'Terry Elbow')&lt;br /&gt;    Pet rex = new Pet(type: 'Dog', name: 'Rex', owner: terry)&lt;br /&gt;    Pet.withSession {session -&gt;&lt;br /&gt;        assert terry.save(flush: true)&lt;br /&gt;        assert rex.save(flush: true)&lt;br /&gt;        session.clear()&lt;br /&gt;    }&lt;br /&gt;    assertEquals(terry, Pet.findByName('Rex').owner)&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void testAssignPirateAsPetOwner() {&lt;br /&gt;    Person longJohn = new Pirate(name: 'John Silver', nickname: 'Long John')&lt;br /&gt;    Pet capnFlint = new Pet(type: 'Parrot', name: "Cap'n Flint", owner: longJohn)&lt;br /&gt;    Pet.withSession {session -&gt;&lt;br /&gt;        assert longJohn.save(flush: true)&lt;br /&gt;        assert capnFlint.save(flush: true)&lt;br /&gt;        session.clear()&lt;br /&gt;    }&lt;br /&gt;    assertEquals(longJohn, Pet.findByName("Cap'n Flint").owner)&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;Simple enough. In both cases we just create a &lt;em&gt;Pet&lt;/em&gt; and its owner, ensure they save properly, then assert that the owner is correct when we read the &lt;em&gt;Pet&lt;/em&gt; back from the database. However the second test, where we assign a &lt;em&gt;Pirate&lt;/em&gt; as the owner, fails. The final assertion fails with the message:&lt;/p&gt;&lt;pre&gt;expected:&amp;lt;Pirate[Long John]&amp;gt; but was:&amp;lt;Pirate[Long John]&amp;gt;&lt;/pre&gt;&lt;p&gt;Great... what?&lt;/p&gt;&lt;p&gt;When we read the &lt;em&gt;Pet&lt;/em&gt; instance back from the database the &lt;em&gt;owner&lt;/em&gt; association is set to lazy load so &lt;code&gt;Pet.findByName("Cap'n Flint").owner&lt;/code&gt; is a &lt;em&gt;HibernateProxy&lt;/em&gt;. The failure is caused by the fact that as &lt;em&gt;owner&lt;/em&gt; is declared as being of type &lt;em&gt;Person&lt;/em&gt; the proxy generated extends &lt;em&gt;Person&lt;/em&gt; and therefore the instanceof check in &lt;em&gt;Pirate&lt;/em&gt;'s equals method fails...&lt;/p&gt;&lt;pre&gt;if (!(o instanceof Pirate)) return false&lt;/pre&gt;&lt;p&gt;In our case &lt;em&gt;o&lt;/em&gt; is an instance of &lt;em&gt;Person&lt;/em&gt; and an instance of &lt;em&gt;HibernateProxy&lt;/em&gt; which if loaded would yield an instance of &lt;em&gt;Pirate&lt;/em&gt; but is not itself an instance of &lt;em&gt;Pirate&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;Our options at this point seem to be...&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Set &lt;em&gt;owner&lt;/em&gt; to eager fetch.&lt;/li&gt;&lt;li&gt;Remove the instanceof check from the &lt;em&gt;equals&lt;/em&gt; implementation in &lt;em&gt;Pirate&lt;/em&gt;&lt;/li&gt;&lt;li&gt;Initialise the &lt;em&gt;HibernateProxy&lt;/em&gt; so &lt;em&gt;equals&lt;/em&gt; is working with the real object&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;The first option is just admitting defeat! Loading objects from the database when it's not necessary is wasteful and we don't want to go creating that kind of tech debt just to get our test working. The second option is not acceptable as it would mean the &lt;em&gt;equals&lt;/em&gt; implementation on &lt;em&gt;Pirate&lt;/em&gt; would violate the &lt;a href="http://java.sun.com/javase/6/docs/api/java/lang/Object.html#equals(java.lang.Object)"&gt;general contract of &lt;em&gt;equals&lt;/em&gt;&lt;/a&gt; as &lt;code&gt;aPerson == aPirate&lt;/code&gt; would return &lt;em&gt;false&lt;/em&gt; but &lt;code&gt;aPirate == aPerson&lt;/code&gt; would throw &lt;em&gt;MissingPropertyException&lt;/em&gt; when it tried to execute the line:&lt;/p&gt;&lt;pre&gt;return nickname == o.nickname&lt;/pre&gt;&lt;p&gt;This leaves us with figuring out a way to initialise the proxy so we're always dealing with real objects. You may think it's an undesirable side-effect of the &lt;em&gt;equals&lt;/em&gt; implementation to potentially force a database read but consider that it will do so anyway to perform the comparison of the &lt;em&gt;nickname&lt;/em&gt; property.&lt;/p&gt;&lt;p&gt;There is a convenience &lt;a href="http://www.hibernate.org/hib_docs/v3/api/org/hibernate/Hibernate.html#initialize(java.lang.Object)"&gt;&lt;em&gt;initialize&lt;/em&gt;&lt;/a&gt; method in &lt;em&gt;org.hibernate.Hibernate&lt;/em&gt; that can force a proxy to load, but it is &lt;em&gt;void&lt;/em&gt; so our &lt;em&gt;equals&lt;/em&gt; method would still have a reference to the &lt;em&gt;HibernateProxy&lt;/em&gt; that is not actually an instance of &lt;em&gt;Pirate&lt;/em&gt;. What we need to do is:&lt;/p&gt;&lt;pre&gt;if (o instanceof org.hibernate.proxy.HibernateProxy) {&lt;br /&gt;    o = o.hibernateLazyInitializer.implementation&lt;br /&gt;}&lt;br /&gt;if (!(o instanceof Pirate)) return false&lt;/pre&gt;&lt;p&gt;As it turns out we can't do this directly in the &lt;em&gt;equals&lt;/em&gt; implementation. It appears that &lt;a href="http://groovy.codehaus.org/groovy-jdk/java/lang/Object.html#getAt(java.lang.String%20property)"&gt;&lt;em&gt;getAt(String)&lt;/em&gt;&lt;/a&gt; is overridden in &lt;em&gt;HibernateProxy&lt;/em&gt;'s meta class so we get the error:&lt;/p&gt;&lt;pre&gt;No such property: hibernateLazyInitializer for class: Person_$$_javassist_0&lt;/pre&gt;&lt;p&gt;As luck would have it Grails has a utility method for doing exactly what we want and as it's written in Java no amount of meta class trickery will hide the &lt;em&gt;hibernateLazyInitializer&lt;/em&gt; property from it. Our final, working &lt;em&gt;equals&lt;/em&gt; implementation for &lt;em&gt;Pirate&lt;/em&gt; looks like:&lt;/p&gt;&lt;pre&gt;boolean equals(Object o) {&lt;br /&gt;    if (!super.equals(o)) return false&lt;br /&gt;    if (o instanceof HibernateProxy) {&lt;br /&gt;        o = GrailsHibernateUtil.unwrapProxy(o)&lt;br /&gt;    }&lt;br /&gt;    if (!(o instanceof Pirate)) return false&lt;br /&gt;    return nickname == o.nickname&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; this is a simple example so we'll gloss over the fact that &lt;em&gt;Pirate&lt;/em&gt;'s &lt;em&gt;equals&lt;/em&gt; isn't symmetric as&lt;/p&gt;&lt;pre&gt;new Person(name: 'X') == new Pirate(name: 'X', nickname: 'Y')&lt;/pre&gt;&lt;p&gt;returns &lt;em&gt;true&lt;/em&gt; while flipping the operands causes it to return &lt;em&gt;false&lt;/em&gt;. The problem and the solution apply any time inheritance and lazy-loading run up against class checking whether via instanceof, &lt;a href="http://java.sun.com/javase/6/docs/api/java/lang/Class.html#isAssignableFrom(java.lang.Class)"&gt;&lt;em&gt;Class.isAssignableFrom&lt;/em&gt;&lt;/a&gt;, switch statements using a Class as a case, etc.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-3233326011054996064?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/3233326011054996064/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=3233326011054996064' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/3233326011054996064'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/3233326011054996064'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2009/04/when-is-pirate-not-pirate-when-its.html' title='When is a Pirate not a Pirate? When it&apos;s a HibernateProxy'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-623622016034752854</id><published>2009-04-02T13:09:00.004+01:00</published><updated>2009-04-02T13:14:59.372+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='intellij'/><category scheme='http://www.blogger.com/atom/ns#' term='grails plugins'/><title type='text'>Grails 1.1 Plugins and IntelliJ Idea</title><content type='html'>Good news. The recent release of the &lt;a href="http://www.jetbrains.net/confluence/display/IDEADEV/Diana+EAP"&gt;IntelliJ Idea EAP&lt;/a&gt; has added proper handling of the new plugin installation system in Grails 1.1 - &lt;em&gt;i.e.&lt;/em&gt; it automatically picks up your plugins installed under &lt;code&gt;~/.grails/1.1/projects/&amp;lt;name&amp;gt;/plugins&lt;/code&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-623622016034752854?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/623622016034752854/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=623622016034752854' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/623622016034752854'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/623622016034752854'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2009/04/grails-11-plugins-and-intellij-idea.html' title='Grails 1.1 Plugins and IntelliJ Idea'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-3496140098053587341</id><published>2009-04-01T12:46:00.007+01:00</published><updated>2009-06-13T08:01:00.277+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='gorm'/><category scheme='http://www.blogger.com/atom/ns#' term='criteria queries'/><title type='text'>Querying By Association With Grails Criteria</title><content type='html'>&lt;p&gt;A common requirement is to select all instances of a domain class where one of its many-to-many associations contains a particular instance of another domain class. Consider these domain classes where a &lt;code&gt;Ship&lt;/code&gt; has a crew composed of &lt;code&gt;Pirate&lt;/code&gt;s and any particular &lt;code&gt;Pirate&lt;/code&gt; can be a part of the crew of several &lt;code&gt;Ship&lt;/code&gt;s:&lt;/p&gt;&lt;pre&gt;class Ship {&lt;br /&gt;   static hasMany = [crew: CrewMember]&lt;br /&gt;   String name&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class CrewMember {&lt;br /&gt;   static belongsTo = [ship: Ship]&lt;br /&gt;   Pirate pirate&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class Pirate {&lt;br /&gt;   String name&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;How can we use a criteria query to find all the &lt;code&gt;Ship&lt;/code&gt; instances where a particular &lt;code&gt;Pirate&lt;/code&gt; is a member of the crew? You might think it's pretty simple, surely:&lt;/p&gt;&lt;pre&gt;Ship.withCriteria {&lt;br /&gt;   crew {&lt;br /&gt;       eq('pirate', blackbeard)&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;However, this has a curious side-effect. For example:&lt;/p&gt;&lt;pre&gt;Ship.withSession {session -&gt;&lt;br /&gt;   blackbeard = new Pirate(name: 'Blackbeard')&lt;br /&gt;   jack = new Pirate(name: 'Calico Jack')&lt;br /&gt;   bart = new Pirate(name: 'Black Bart')&lt;br /&gt;   [blackbeard, jack, bart]*.save()&lt;br /&gt;&lt;br /&gt;   def ship1 = new Ship(name: "Queen Anne's Revenge")&lt;br /&gt;   ship1.addToCrew new CrewMember(pirate: blackbeard)&lt;br /&gt;   ship1.addToCrew new CrewMember(pirate: jack)&lt;br /&gt;&lt;br /&gt;   def ship2 = new Ship(name: "Royal Fortune")&lt;br /&gt;   ship2.addToCrew new CrewMember(pirate: blackbeard)&lt;br /&gt;   ship2.addToCrew new CrewMember(pirate: bart)&lt;br /&gt;&lt;br /&gt;   def ship3 = new Ship(name: "The Treasure")&lt;br /&gt;   ship3.addToCrew new CrewMember(pirate: jack)&lt;br /&gt;   ship3.addToCrew new CrewMember(pirate: bart)&lt;br /&gt;&lt;br /&gt;   [ship1, ship2, ship3]*.save()&lt;br /&gt;&lt;br /&gt;   session.flush()&lt;br /&gt;   session.clear()&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;def blackbeardsShips = Ship.withCriteria {&lt;br /&gt;   crew {&lt;br /&gt;       eq('pirate', blackbeard)&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;blackbeardsShips.each {&lt;br /&gt;   println "$it.name: ${it.crew.pirate.name.join(', ')}"&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;You might expect the output to be:&lt;/p&gt;&lt;pre&gt;Queen Anne's Revenge: Blackbeard, Calico Jack&lt;br /&gt;Royal Fortune: Blackbeard, Black Bart&lt;/pre&gt;&lt;p&gt;but it is actually:&lt;/p&gt;&lt;pre&gt;Queen Anne's Revenge: Blackbeard&lt;br /&gt;Royal Fortune: Blackbeard&lt;/pre&gt;&lt;p&gt;The criteria query has restricted the content of the associations to only the ones matching the &lt;code&gt;eq('pirate', blackbeard)&lt;/code&gt; criterion. This is quite a problem as it may well not be immediately obvious that it's happened and even using &lt;code&gt;ships*.refresh()&lt;/code&gt; (which would be a horrible hack, especially if we were likely to get more than a couple of results) doesn't seem to restore the missing entries. I don't think there &lt;em&gt;is&lt;/em&gt; any criterion that does a 'contains' type match for a persistent collection. My guess is this problem isn't a Grails thing but a Hibernate thing - Grails' &lt;a href="http://grails.org/doc/1.1.x/ref/Domain%20Classes/createCriteria.html"&gt;&lt;code&gt;HibernateCriteriaBuilder&lt;/code&gt;&lt;/a&gt; is a very thin layer over Hibernate itself.&lt;/p&gt;&lt;p&gt;In &lt;em&gt;this&lt;/em&gt; example there is an alternative as the association is bi-directional. We can query from the other side of the association:&lt;/p&gt;&lt;pre&gt;def blackbeardsShips = CrewMember.withCriteria {&lt;br /&gt;   projections {&lt;br /&gt;       property('ship')&lt;br /&gt;   }&lt;br /&gt;   eq('pirate', blackbeard)&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;If the association wasn't bidirectional this wouldn't be possible and we'd probably have to resort to using HQL to make the query exhibit the correct behaviour.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-3496140098053587341?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/3496140098053587341/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=3496140098053587341' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/3496140098053587341'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/3496140098053587341'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2009/04/associations-and-criteria-queries.html' title='Querying By Association With Grails Criteria'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-835106034374885931</id><published>2009-03-31T14:55:00.002+01:00</published><updated>2009-03-31T15:24:28.149+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gorm'/><category scheme='http://www.blogger.com/atom/ns#' term='joda time'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><title type='text'>Joda-Time and Grails Auto-Timestamping</title><content type='html'>&lt;p&gt;The &lt;a href="http://grails.org/JodaTime+Plugin"&gt;Joda-Time Plugin docs&lt;/a&gt; state that &lt;a href="http://grails.org/doc/1.1.x/guide/5.%20Object%20Relational%20Mapping%20(GORM).html#5.5.1%20Events%20and%20Auto%20Timestamping"&gt;Grails' auto-timestamping&lt;/a&gt; works with Joda-Time properties which is the case. However, when testing it can be useful to take advantage of Joda Time's &lt;a href="http://joda-time.sourceforge.net/api-release/org/joda/time/DateTimeUtils.html"&gt;&lt;code&gt;DateTimeUtils&lt;/code&gt;&lt;/a&gt; class to mock the current time. This enables you to have new &lt;code&gt;DateTime&lt;/code&gt; objects, for example, use a predictable timestamp. Unfortunately it doesn't play nicely with Grails' auto-timestamping which under the covers uses &lt;code&gt;System.currentTimeMillis()&lt;/code&gt;. There are a couple of solutions to this. You can disable the auto-timestamping and define your own &lt;code&gt;beforeInsert&lt;/code&gt; event which enables you to use &lt;a href="http://joda-time.sourceforge.net/api-release/org/joda/time/DateTimeUtils.html#setCurrentMillisFixed(long)"&gt;&lt;code&gt;DateTimeUtils.setCurrentMillisFixed&lt;/code&gt;&lt;/a&gt;. For example:&lt;/p&gt;&lt;pre&gt;static mapping = {&lt;br /&gt;    autoTimestamp false&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;def beforeInsert = {&lt;br /&gt;    dateCreated = new DateTime()&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;The other option would be to mock out the value returned by &lt;code&gt;System.currentTimeMillis()&lt;/code&gt;. This has the advantage of meaning you don't have to add code to your domain class to enable tests to work, but on the other hand it's all to easy to have such meta class modifications leak from test to test by not being torn down properly.&lt;/p&gt;&lt;p&gt;On a related note the next release of the Joda-Time plugin will bind additional methods to &lt;code&gt;DateTimeUtils&lt;/code&gt; to scope mocking of the current timestamp, for example:&lt;/p&gt;&lt;pre&gt;DateTimeUtils.withCurrentMillisFixed(aLong) {&lt;br /&gt;    // do some stuff that requires a mocked current time&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;No more forgetting to call &lt;code&gt;DateTimeUtils.setCurrentMillisSystem()&lt;/code&gt; in your &lt;code&gt;tearDown&lt;/code&gt; method!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-835106034374885931?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/835106034374885931/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=835106034374885931' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/835106034374885931'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/835106034374885931'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2009/03/joda-time-and-grails-auto-timestamping.html' title='Joda-Time and Grails Auto-Timestamping'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-1260731943371394008</id><published>2009-03-10T09:30:00.008Z</published><updated>2010-09-27T13:16:52.672+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='spring'/><category scheme='http://www.blogger.com/atom/ns#' term='i18n'/><title type='text'>Internationalizing Domain Classes and Enums</title><content type='html'>&lt;p&gt;It's common to provide a &lt;code&gt;toString&lt;/code&gt; implementation on a domain object that may well end up being used in the view. However, this doesn't allow for internationalization in the view. A good solution that I've used a number of times is to have classes implement Spring's &lt;a href="http://static.springframework.org/spring/docs/2.5.x/api/org/springframework/context/MessageSourceResolvable.html"&gt;MessageSourceResolvable&lt;/a&gt; interface. Consider this domain class that represents an image file:&lt;/p&gt;&lt;h4&gt;grails-app/domain/Image.groovy&lt;/h4&gt;&lt;pre&gt;class Image {&lt;br /&gt;    String name&lt;br /&gt;    String path&lt;br /&gt;    User uploadedBy&lt;br /&gt;    org.joda.time.DateTime dateCreated&lt;br /&gt;&lt;br /&gt;    static transients = ['file']&lt;br /&gt;    File getFile() {&lt;br /&gt;        new File(ConfigurationHolder.config.image.base.dir, path)&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    String toString() {&lt;br /&gt;        "$name uploaded by $uploadedBy.username on $dateCreated - ${file.size()} bytes"&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;toString&lt;/code&gt; implementation is all well and good if we're targeting an English-speaking audience but with some simple changes we can make it i18n compliant:&lt;/p&gt;&lt;h4&gt;grails-app/domain/Image.groovy&lt;/h4&gt;&lt;pre&gt;class Image implements org.springframework.context.MessageSourceResolvable {&lt;br /&gt;&lt;br /&gt;    // properties as above&lt;br /&gt;&lt;br /&gt;    static transients = ["codes", "arguments", "defaultMessage"]&lt;br /&gt;&lt;br /&gt;    Object[] getArguments() {&lt;br /&gt;        [name, uploadedBy.username, dateCreated.toDate(), file.size()] as Object[]&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    String[] getCodes() {&lt;br /&gt;        ['image.info'] as String[]&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    String getDefaultMessage() {&lt;br /&gt;        "$name uploaded by $uploadedBy.username on $dateCreated - ${file.size()} bytes"&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;In our message properties file we can add:&lt;/p&gt;&lt;h4&gt;grails-app/i18n/messages.properties&lt;/h4&gt;&lt;pre&gt;image.info={0} uploaded by {1} on {2,date} - ${3,number,integer} bytes&lt;/pre&gt;&lt;p&gt;In the view we can display our object like this:&lt;/p&gt;&lt;pre&gt;&amp;lt;g:message error="${imageInstance}"/&amp;gt;&lt;/pre&gt;&lt;p&gt;Yes, that is the &lt;code&gt;error&lt;/code&gt; attribute we're passing to the message tag! Grails intends the attribute to be used for outputting validation errors but the underlying mechanism is the same - Spring's &lt;a href="http://static.springframework.org/spring/docs/2.5.x/api/org/springframework/validation/ObjectError.html"&gt;&lt;code&gt;ObjectError&lt;/code&gt;&lt;/a&gt; implements &lt;code&gt;MessageSourceResolvable&lt;/code&gt; and that's how Grails' message tag resolves the displayed error message. Rather than passing separate &lt;code&gt;code&lt;/code&gt;, &lt;code&gt;args&lt;/code&gt; and &lt;code&gt;default&lt;/code&gt; attributes to the tag we can pass the single &lt;code&gt;MessageSourceResolvable&lt;/code&gt; instance and its implementation will take care of supplying those values.&lt;/p&gt;&lt;p&gt;&lt;em&gt;Note: I added a &lt;code&gt;message&lt;/code&gt; attribute to the message tag to avoid the confusion caused by using &lt;code&gt;error&lt;/code&gt;. This is in Grails from version 1.2-M1 onwards.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;We can now add translations of our object description. For example:&lt;/p&gt;&lt;h4&gt;grails-app/i18n/messages_af.properties&lt;/h4&gt;&lt;pre&gt;image.info={0} opgelaai deur {1} op {2,date} - ${3,number,integer} grepe&lt;/pre&gt;&lt;p&gt;It's worth noting that the format of the &lt;code&gt;dateCreated&lt;/code&gt; property will be automatically determined by the request locale so the value will be formatted correctly for the user.&lt;/p&gt;&lt;p&gt;I've found this technique can also be very useful on enum classes. For example:&lt;/p&gt;&lt;h4&gt;src/groovy/com/mycompany/Season.groovy&lt;/h4&gt;&lt;pre&gt;package com.mycompany&lt;br /&gt;&lt;br /&gt;enum Season implements org.springframework.context.MessageSourceResolvable {&lt;br /&gt;    SPRING, SUMMER, AUTUMN, WINTER&lt;br /&gt;&lt;br /&gt;    Object[] getArguments() { [] as Object[] }&lt;br /&gt;&lt;br /&gt;    String[] getCodes() {&lt;br /&gt;        ["${getClass().name}.${name()}"] as String[]&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    String getDefaultMessage() { name() }&lt;br /&gt;}&lt;/pre&gt;&lt;h4 style="margin-top: 1em;"&gt;grails-app/i18n/messages.properties&lt;/h4&gt;&lt;pre&gt;com.mycompany.Season.SPRING=Spring&lt;br /&gt;com.mycompany.Season.SUMMER=Summer&lt;br /&gt;com.mycompany.Season.AUTUMN=Autumn&lt;br /&gt;com.mycompany.Season.WINTER=Winter&lt;/pre&gt;&lt;h4 style="margin-top: 1em;"&gt;grails-app/i18n/messages_en_US.properties&lt;/h4&gt;&lt;pre&gt;com.mycompany.Season.AUTUMN=Fall&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-1260731943371394008?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/1260731943371394008/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=1260731943371394008' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/1260731943371394008'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/1260731943371394008'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2009/03/internationalizing-domain-classes-and.html' title='Internationalizing Domain Classes and Enums'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-4202094558730218468</id><published>2009-03-03T13:31:00.005Z</published><updated>2009-03-31T14:30:32.505+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='gorm'/><category scheme='http://www.blogger.com/atom/ns#' term='joda time'/><title type='text'>Persisting DateTime with zone information</title><content type='html'>&lt;p&gt;I was stuck a while ago trying to figure out how to map &lt;a href="http://joda-time.sourceforge.net/contrib/hibernate/apidocs/org/joda/time/contrib/hibernate/PersistentDateTimeTZ.html"&gt;&lt;code&gt;PersistentDateTimeTZ&lt;/code&gt;&lt;/a&gt; in a GORM class. It's an implementation of Hibernate's &lt;a href="http://www.hibernate.org/hib_docs/v3/api/org/hibernate/usertype/UserType.html"&gt;&lt;code&gt;UserType&lt;/code&gt;&lt;/a&gt; interface that persists a Joda &lt;a href="http://joda-time.sourceforge.net/api-release/org/joda/time/DateTime.html"&gt;&lt;code&gt;DateTime&lt;/code&gt;&lt;/a&gt; value using 2 columns - one for the actual timestamp and one for the time zone. The &lt;code&gt;DateTime&lt;/code&gt; class contains time zone information but a SQL timestamp column is time zone agnostic so you can lose data when the value is saved (the same exact problem exists when persisting &lt;code&gt;java.util.Date&lt;/code&gt; values).&lt;/p&gt;&lt;p&gt;I could never figure out how to map the user type to my domain class property correctly. Just doing:&lt;/p&gt;&lt;pre&gt;static mapping = {&lt;br /&gt;    dateTimeProperty type: PersistentDateTimeTZ&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;Failed with:&lt;/p&gt;&lt;pre&gt;org.hibernate.MappingException: property mapping has wrong number of columns.&lt;/pre&gt;&lt;p&gt;I seem to remember someone on the Grails mailing list suggesting I tried treating the value as an &lt;a href="http://grails.org/doc/1.1.x/guide/single.html#5.2.2%20Composition%20in%20GORM"&gt;embedded type&lt;/a&gt;. That also didn't work as &lt;a href="http://jira.codehaus.org/browse/GRAILS-3328"&gt;GORM embedded types have to be Groovy classes in &lt;code&gt;grails-app/domain&lt;/code&gt;&lt;/a&gt; and &lt;code&gt;PersistentDateTimeTZ&lt;/code&gt; is written in Java and lives in a library jar.&lt;/p&gt;&lt;p&gt;I finally found the solution in the &lt;a href="http://www.amazon.co.uk/Definitive-Guide-Grails-Experts-Development/dp/1590599950"&gt;2nd Edition of The Definitive Guide to Grails&lt;/a&gt; (which I can't recommend enough, by the way). The trick is to pass a closure specifying the two columns to the property definition in the mapping builder. The working code looks like this:&lt;/p&gt;&lt;pre&gt;static mapping = {&lt;br /&gt;    dateTimeProperty type: PersistentDateTimeTZ, {&lt;br /&gt;        column name: "date_time_property_timestamp"&lt;br /&gt;        column name: "date_time_property_zone"&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;The order of the columns corresponds to the order of the values returned by &lt;a href="http://www.hibernate.org/hib_docs/v3/api/org/hibernate/usertype/UserType.html#sqlTypes()"&gt;the &lt;code&gt;sqlTypes()&lt;/code&gt; method&lt;/a&gt; of whatever &lt;code&gt;UserType&lt;/code&gt; implementation you're using.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-4202094558730218468?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/4202094558730218468/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=4202094558730218468' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/4202094558730218468'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/4202094558730218468'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2009/03/persisting-datetime-with-zone.html' title='Persisting DateTime with zone information'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-638202321047795282</id><published>2009-03-02T17:28:00.000Z</published><updated>2009-03-02T17:28:40.773Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='caching'/><category scheme='http://www.blogger.com/atom/ns#' term='hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='gorm'/><title type='text'>Why would I ever want to disable the L2 cache?</title><content type='html'>&lt;p&gt;This question came up when pairing last week. We were going through our code-base adding the &lt;a href="http://grails.org/doc/1.1.x/ref/Database%20Mapping/cache.html"&gt;cache directive&lt;/a&gt; to a bunch of our domain classes. Grails is all about sensible defaults and it seems slightly odd that the level 2 cache is configured by default in &lt;code&gt;DataSource.groovy&lt;/code&gt; but not actually &lt;em&gt;used&lt;/em&gt; unless &lt;code&gt;cache(true)&lt;/code&gt; is added to the mapping closure in each domain class. I wonder if anyone has any ideas why it might ever be a bad idea to use the L2 cache?&lt;/p&gt;&lt;p&gt;The only scenario I can come up with is situations where updates are made direct to the DB, bypassing Hibernate. This is, I would think, pretty rare (we do it for some rather na&amp;iuml;ve hit tracking and for voting on polls). Sure, in this circumstance the L2 cache will likely give you stale results. However, it's very much the exception rather than the rule.&lt;/p&gt;&lt;p&gt;Most other objections I've heard have been some variety of worry about caches eating up vast amounts of heap space and crashing the JVM (which is why cache implementations like &lt;a href="http://ehcache.sourceforge.net/"&gt;ehcache&lt;/a&gt; use time-based and LRU eviction).&lt;/p&gt;&lt;p&gt;Oh, and yeah, we did have some issues with our changes but most seem to be to do with &lt;a href="http://www.catb.org/jargon/html/C/cruft.html"&gt;cruft&lt;/a&gt; and &lt;a href="http://www.think-box.co.uk/blog/2005/11/repaying-technical-debt.html"&gt;tech debt&lt;/a&gt; in our code (mostly now-redundant workarounds to GORM issues from older releases of Grails).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-638202321047795282?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/638202321047795282/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=638202321047795282' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/638202321047795282'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/638202321047795282'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2009/03/why-would-i-ever-want-to-disable-l2.html' title='Why would I ever want to disable the L2 cache?'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-213973752435838370</id><published>2009-03-01T11:21:00.000Z</published><updated>2009-03-01T11:21:09.660Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='gorm'/><category scheme='http://www.blogger.com/atom/ns#' term='immutable'/><title type='text'>Hibernate POGOs, Immutability and Encapsulation</title><content type='html'>&lt;p&gt;I had a confusing experience this morning. I'm working on a simple web based game as a learning exercise.&lt;/p&gt;&lt;p&gt;I use a custom tag to determine if the currently logged in user is the active player (i.e. the player whose turn it is).&lt;/p&gt;&lt;pre&gt;  &amp;lt;g:isNextPlayer&amp;gt;&lt;br /&gt;    &amp;lt;!-- display something only active player should see --&amp;gt;&lt;br /&gt;  &amp;lt;/g:isNextPlayer&amp;gt;&lt;/pre&gt;&lt;p&gt;The tag is used at various places in the page - displaying an "it's your turn" message, switching on bits of script, rendering buttons, etc. Suddenly I found the last couple of calls to the tag in a page weren't rendering the tag body.&lt;/p&gt;&lt;p&gt;The tag uses a transient property on the &lt;code&gt;Game&lt;/code&gt; domain class that looks like this:&lt;/p&gt;&lt;pre&gt;  Player getNextPlayer() {&lt;br /&gt;    return players.empty ? null : players[turn % players.size()]&lt;br /&gt;  }&lt;/pre&gt;&lt;p&gt;The variable &lt;code&gt;turn&lt;/code&gt; is simply an integer that gets incremented when a turn completes.&lt;/p&gt;&lt;p&gt;After poking around with debug logging I figured out that the implementation of &lt;code&gt;getNextPlayer&lt;/code&gt; was fine and the value of &lt;code&gt;turn&lt;/code&gt; wasn't being accidentally changed but the collection property &lt;code&gt;players&lt;/code&gt; was getting re-ordered. What I'd done was introduce some code mid-way in the page that displays the players' names and scores - &lt;em&gt;ordered by score.&lt;/em&gt;&lt;/p&gt;&lt;pre&gt;  &amp;lt;g:each var="player" in="${gameInstance.players.sort { -it.score }}"&amp;gt;&lt;br /&gt;    &amp;lt;tr&amp;gt;&lt;br /&gt;      &amp;lt;td&amp;gt;${player.user.username}&amp;lt;/td&amp;gt;&lt;br /&gt;      &amp;lt;td&amp;gt;${player.score}&amp;lt;/td&amp;gt;&lt;br /&gt;    &amp;lt;/tr&amp;gt;&lt;br /&gt;  &amp;lt;/g:each&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;I had assumed when I did this that &lt;a href="http://groovy.codehaus.org/groovy-jdk/java/util/Collection.html#sort(groovy.lang.Closure%20closure)"&gt;&lt;code&gt;Collection.sort(Closure)&lt;/code&gt;&lt;/a&gt; would return a copy (which &lt;em&gt;is&lt;/em&gt; what the docs state - not that I'd checked). However, it seems that is only the case if the collection it's called on is not a &lt;code&gt;List&lt;/code&gt;. On &lt;code&gt;List&lt;/code&gt; instances the method acts as a mutator and does an in-place sort.&lt;/p&gt;&lt;pre&gt;  def c = [1,2,3] as Set&lt;br /&gt;  def s = c.sort { it }&lt;br /&gt;  assert !(c.is(s))&lt;/pre&gt;&lt;p&gt;Remove the '&lt;code&gt;as Set&lt;/code&gt;' and the assertion fails.&lt;/p&gt;&lt;p&gt;Although I'd argue that Groovy's sort implementation doesn't exactly stick to the principal of least surprise that's not really what concerns me. In my domain it doesn't make sense for me to be able to mutate the &lt;code&gt;players&lt;/code&gt; property of &lt;code&gt;Game&lt;/code&gt;. Once a game is created the players are fixed, they can't leave, can't take turns out of order. The state of an individual &lt;code&gt;Player&lt;/code&gt; can change - his score can change, for example, but not the collection property of &lt;code&gt;Game&lt;/code&gt;. In a regular non-persistent class this sort of invariant would be enforced by overriding the getter and setter:&lt;/p&gt;&lt;pre&gt;  private List players&lt;br /&gt;  List getPlayers() { players.asImmutable() }&lt;br /&gt;  void setPlayers(List players) {&lt;br /&gt;    this.players = []&lt;br /&gt;    this.players.addAll players&lt;br /&gt;  }&lt;/pre&gt;&lt;p&gt;If my &lt;code&gt;Game&lt;/code&gt; class was implemented that way I'd have got an &lt;code&gt;UnsupportedOperationException&lt;/code&gt; from the &lt;code&gt;sort&lt;/code&gt; call. If nothing else it would have saved me 5 minutes of "&lt;em&gt;WTF?&lt;/em&gt;" and 10 minutes of trying to figure out if it was something to do with the second-level cache. Unfortunately, this technique doesn't quite work satisfactorily in a GORM domain class though. For a start declaring the property as &lt;code&gt;private&lt;/code&gt; will result in a compilation failure - &lt;em&gt;'The field 'players' is declared multiple times.'&lt;/em&gt; Declaring the property without &lt;code&gt;private&lt;/code&gt; gets you past the compilation phase but Grails &lt;a href="http://grails.org/doc/1.1.x/ref/Domain%20Classes/addTo.html"&gt;'addTo*'&lt;/a&gt; dynamic method isn't bound.&lt;/p&gt;&lt;p&gt;One of the things that's always nagged at the back of my mind when using GORM/Hibernate is the fact that all to often the domain classes end up resembling the &lt;a href="http://en.wikipedia.org/wiki/Anemic_Domain_Model"&gt;an&amp;aelig;mic domain model anti-pattern&lt;/a&gt; even to the extent of a design something like &lt;a href="http://www.stateofflow.com/journal/57/object-disorientation"&gt;the cautionary tale of POTS&lt;/a&gt;. I like to put a certain amount of business logic in my domain classes and give them a reasonably rich API for managing their state without violating encapsulation but there's always an uncomfortable feeling that properties that really should be part of an object's private state are hanging out in the wind so that the persistence framework can access them.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-213973752435838370?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/213973752435838370/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=213973752435838370' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/213973752435838370'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/213973752435838370'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2009/03/hibernate-pogos-immutability-and.html' title='Hibernate POGOs, Immutability and Encapsulation'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9390811.post-5516841929592143815</id><published>2009-02-12T06:05:00.001Z</published><updated>2009-02-12T06:05:09.116Z</updated><title type='text'>Watchmen Widget</title><content type='html'>&lt;object width="375" height="375"&gt;&lt;param name="wmode" value="transparent" /&gt;&lt;param name="allowFullScreen" value="true" /&gt;&lt;param name="movie" value="http://www.ppiwidget.com/campaigns/as3base.swf?inst_id=538784"/&gt;&lt;embed src="http://www.ppiwidget.com/campaigns/as3base.swf?inst_id=538784" type="application/x-shockwave-flash" width="375" height="375" wmode="transparent" allowFullScreen="true"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9390811-5516841929592143815?l=adhockery.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adhockery.blogspot.com/feeds/5516841929592143815/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9390811&amp;postID=5516841929592143815' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/5516841929592143815'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9390811/posts/default/5516841929592143815'/><link rel='alternate' type='text/html' href='http://adhockery.blogspot.com/2009/02/watchmen-widget.html' title='Watchmen Widget'/><author><name>Rob</name><uri>http://www.blogger.com/profile/01855523354151116481</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp1.blogger.com/_fh9xwLFYBUw/SA80KDlovfI/AAAAAAAABxo/y56XWw_XQfE/S220/blackbeard.jpg'/></author><thr:total>0</thr:total></entry></feed>
