Fork me on GitHub
Showing posts with label gorm. Show all posts
Showing posts with label gorm. Show all posts

29 Jun 2010

Acyclic relationship validation in Grails

A common domain class use-case is for a self-referential relationship that must not be circular (a directed acyclic graph). For example, a Person class may have a parent property that is a many-to-one relationship with another Person instance. However a given Person cannot be his own parent or ancestor.

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:Then I just needed to register my new constraint by adding ConstrainedProperty.registerNewConstraint(AcyclicConstraint.NAME, AcyclicConstraint) to grails-app/conf/spring/resources.groovy. Using the constraint is as simple as this:
class Person {

    String name
    Person parent

    static constraints = {
        parent acyclic: true
    }
}
The constraint can be mixed with others such as nullable: true. 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.

When you're using similar validation logic in multiple classes defining a constraint like this is a much better option than using a validator closure and like many things in Grails it turns out to be pretty easy to implement.

24 Jun 2010

Defaulting Joda Time Hibernate Types with Grails

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 java.util.Date in your domain objects. Previously you had to specify the Hibernate user type for every single field, like this:
import org.joda.time.*
import org.joda.time.contrib.hibernate.*

DateTime dateCreated
DateTime lastUpdated
LocalDate birthday

static mapping = {
    dateCreated type: PersistentDateTime
    lastUpdated type: PersistentDateTime
    birthday type: PersistentLocalDate
}
Now you can just add this to your Config.groovy once and do away with the type mappings in the individual classes:
grails.gorm.default.mapping = {
    "user-type" type: PersistentDateTime, class: DateTime
    "user-type" type: PersistentLocalDate, class: LocalDate
}
Correction: 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 user-type. Apologies for the error.

I'll look into the possibility of the Joda-Time plugin doing this itself to make things even easier.

25 Feb 2010

Using a custom data binder with Grails domain objects

Yesterday I read a post by Stefan Armbruster 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.

For example, let's say I have Artist and Album domain classes where Artist hasMany Albums and Album belongsTo Artist. Artist has a name property that is unique. On my create album page I want to be able to type in the artist name and have the save action in the controller automatically lookup an existing Artist 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 save action itself - I could theoretically use dynamic scaffolding.

Adapting Stefan's PropertyEditor implementation I created this:
The crucial change is the if (!value) block which creates the new instance and populates the relevant property.

To make everything work I just need to:
  1. Add the PropertyEditorRegistrar and place it in resources.groovy as per Stefan's post.
  2. Have a text input or autocompleter with the name "artist" in my create album form.
  3. Add artist cascade: "save-update" to the mapping block in Album so that when the Album is saved the new Album will get saved as well.

4 Jan 2010

Upgrading Grails 1.1 -> 1.2

We've just successfully upgraded our app from Grails 1.1 to 1.2 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.


Custom constraints that execute queries

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 StackOverflowError; the query causes the session to flush, causing the object to be validated, causing the query to run, causing the session to flush, etc.

The solution is to use one of the new domain class dynamic methods withNewSession to execute the query in a separate Hibernate session.

For example, we have a domain class where only a single instance can exist in a 'live' state. A simple unique constraint won't work as any number of instances can exist in other states. The final constraint looks something like this:

static constraints = {
    state validator: { value, self ->
        boolean valid = true
        if (value == State.LIVE) {
            Homepage.withNewSession {
                valid = Homepage.countByStateAndIdNotEqual(State.LIVE, self.id) == 0
            }
        }
        return valid
    }
}

Errors set outside constraints

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.

The validation code in the controller looks something like this:

domainInstance.validate()
if (domainInstance.goLiveTime < new Date()) {
    domainInstance.rejectValue "goLiveTime", "min.notMet"
}
if (!domainInstance.hasErrors() && domainInstance.save()) {
    // redirect
} else {
    // re-render form with errors
}

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.

If save 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 else block before rendering the form using GrailsHibernateUtil.setObjectToReadOnly(domainInstance, sessionFactory). 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.

Specifying fetch modes on associations in criteria queries

We have one particularly nasty query that retrieves a domain object instance and loads an entire hierarchy of associations using several fetchMode "property", FetchMode.JOIN in the criteria query. For example if Author has many books and each Book has many chapters the query previously looked like:

Author.withCriteria {
    // some criteria
    fetchMode "books", FetchMode.JOIN
    fetchMode "chapters", FetchMode.JOIN
}

This always seemed syntactically odd as it appears that chapters is a property of Author when it is in fact a property of each member of Author.books. In Grails 1.2 the syntax makes much more sense as you nest the fetchMode declarations just as you would other criteria. So the example above would become:

Author.withCriteria {
    // some criteria
    fetchMode "books", FetchMode.JOIN
    books {
        fetchMode "chapters", FetchMode.JOIN
    }
}

Date binding format

Date binding now uses a fixed format of yyyy-MM-dd HH:mm:ss.S 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 dd/MM/yy. In order to keep this functionality working I had to create a class that implements PropertyEditorRegistrar and deploy it in grails-app/conf/spring/resources.groovy. The class registers a custom date editor using the required format.

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).

Setting String values in g:set tags

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 String instances where possible. One minor change I had to make to support this was changing g:set tags in the format <g:set var="name">${value}</g:set> to <g:set var="name" value="${value}"/> Variable created in the first manner are now instances of StreamCharBuffer rather than java.lang.String which sometimes caused problems when they were used later.

Flash scope and null values

The flash scope object available to controllers is now an instance of ConcurrentHashMap which means none of its keys can map to null. There were a few places where we were setting flash.message to the result of a method call that might return null. I simply ensured the empty string was used instead.

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.

18 Jun 2009

Joda Time Auto-Timestamping Issue on Grails 1.1.1

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

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

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

DateTime dateCreated
DateTime lastUpdated

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

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

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

DateTime dateCreated
DateTime lastUpdated

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

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

13 Jun 2009

Querying by Association Redux

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

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

To recap. If I have these domain classes:

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

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

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

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

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

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

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

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

class PirateTests extends GroovyTestCase {

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

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

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

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

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

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

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

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

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

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

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

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

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

The second (correct) query is:

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

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

15 Apr 2009

When is a Pirate not a Pirate? When it's a HibernateProxy

At work we're in the middle of upgrading the Sky Entertainment sites 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 HibernateProxy instances where before we weren't.

For example, let's imagine we have a Pet domain class that is has an owner that is a Person and there exists another domain class, Pirate that is a specialisation of Person:

Pet.groovy

class Pet {
String type
String name
Person owner
}

Person.groovy

class Person {

String name

boolean equals(Object o) {
if (this.is(o)) return true
if (o == null) return false
if (!(o instanceof Person)) return false
return name == o.name
}


// hashCode and toString ommitted
}

Pirate.groovy

class Pirate extends Person {

String nickname

boolean equals(Object o) {
if (!super.equals(o)) return false
if (!(o instanceof Pirate)) return false
return nickname == o.nickname
}

// hashCode and toString ommitted
}

We want to test that either a regular Person or a Pirate can own a Pet. To do so we write an integration test like this:

void testAssignPersonAsPetOwner() {
Person terry = new Person(name: 'Terry Elbow')
Pet rex = new Pet(type: 'Dog', name: 'Rex', owner: terry)
Pet.withSession {session ->
assert terry.save(flush: true)
assert rex.save(flush: true)
session.clear()
}
assertEquals(terry, Pet.findByName('Rex').owner)
}

void testAssignPirateAsPetOwner() {
Person longJohn = new Pirate(name: 'John Silver', nickname: 'Long John')
Pet capnFlint = new Pet(type: 'Parrot', name: "Cap'n Flint", owner: longJohn)
Pet.withSession {session ->
assert longJohn.save(flush: true)
assert capnFlint.save(flush: true)
session.clear()
}
assertEquals(longJohn, Pet.findByName("Cap'n Flint").owner)
}

Simple enough. In both cases we just create a Pet and its owner, ensure they save properly, then assert that the owner is correct when we read the Pet back from the database. However the second test, where we assign a Pirate as the owner, fails. The final assertion fails with the message:

expected:<Pirate[Long John]> but was:<Pirate[Long John]>

Great... what?

When we read the Pet instance back from the database the owner association is set to lazy load so Pet.findByName("Cap'n Flint").owner is a HibernateProxy. The failure is caused by the fact that as owner is declared as being of type Person the proxy generated extends Person and therefore the instanceof check in Pirate's equals method fails...

if (!(o instanceof Pirate)) return false

In our case o is an instance of Person and an instance of HibernateProxy which if loaded would yield an instance of Pirate but is not itself an instance of Pirate.

Our options at this point seem to be...

  1. Set owner to eager fetch.
  2. Remove the instanceof check from the equals implementation in Pirate
  3. Initialise the HibernateProxy so equals is working with the real object

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 equals implementation on Pirate would violate the general contract of equals as aPerson == aPirate would return false but aPirate == aPerson would throw MissingPropertyException when it tried to execute the line:

return nickname == o.nickname

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 equals implementation to potentially force a database read but consider that it will do so anyway to perform the comparison of the nickname property.

There is a convenience initialize method in org.hibernate.Hibernate that can force a proxy to load, but it is void so our equals method would still have a reference to the HibernateProxy that is not actually an instance of Pirate. What we need to do is:

if (o instanceof org.hibernate.proxy.HibernateProxy) {
o = o.hibernateLazyInitializer.implementation
}
if (!(o instanceof Pirate)) return false

As it turns out we can't do this directly in the equals implementation. It appears that getAt(String) is overridden in HibernateProxy's meta class so we get the error:

No such property: hibernateLazyInitializer for class: Person_$$_javassist_0

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 hibernateLazyInitializer property from it. Our final, working equals implementation for Pirate looks like:

boolean equals(Object o) {
if (!super.equals(o)) return false
if (o instanceof HibernateProxy) {
o = GrailsHibernateUtil.unwrapProxy(o)
}
if (!(o instanceof Pirate)) return false
return nickname == o.nickname
}

Note: this is a simple example so we'll gloss over the fact that Pirate's equals isn't symmetric as

new Person(name: 'X') == new Pirate(name: 'X', nickname: 'Y')

returns true while flipping the operands causes it to return false. The problem and the solution apply any time inheritance and lazy-loading run up against class checking whether via instanceof, Class.isAssignableFrom, switch statements using a Class as a case, etc.

1 Apr 2009

Querying By Association With Grails Criteria

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 Ship has a crew composed of Pirates and any particular Pirate can be a part of the crew of several Ships:

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

class CrewMember {
static belongsTo = [ship: Ship]
Pirate pirate
}

class Pirate {
String name
}

How can we use a criteria query to find all the Ship instances where a particular Pirate is a member of the crew? You might think it's pretty simple, surely:

Ship.withCriteria {
crew {
eq('pirate', blackbeard)
}
}

However, this has a curious side-effect. For example:

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

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

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

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

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

session.flush()
session.clear()
}

def blackbeardsShips = Ship.withCriteria {
crew {
eq('pirate', blackbeard)
}
}
blackbeardsShips.each {
println "$it.name: ${it.crew.pirate.name.join(', ')}"
}

You might expect the output to be:

Queen Anne's Revenge: Blackbeard, Calico Jack
Royal Fortune: Blackbeard, Black Bart

but it is actually:

Queen Anne's Revenge: Blackbeard
Royal Fortune: Blackbeard

The criteria query has restricted the content of the associations to only the ones matching the eq('pirate', blackbeard) criterion. This is quite a problem as it may well not be immediately obvious that it's happened and even using ships*.refresh() (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 is 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' HibernateCriteriaBuilder is a very thin layer over Hibernate itself.

In this example there is an alternative as the association is bi-directional. We can query from the other side of the association:

def blackbeardsShips = CrewMember.withCriteria {
projections {
property('ship')
}
eq('pirate', blackbeard)
}

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.

31 Mar 2009

Joda-Time and Grails Auto-Timestamping

The Joda-Time Plugin docs state that Grails' auto-timestamping works with Joda-Time properties which is the case. However, when testing it can be useful to take advantage of Joda Time's DateTimeUtils class to mock the current time. This enables you to have new DateTime objects, for example, use a predictable timestamp. Unfortunately it doesn't play nicely with Grails' auto-timestamping which under the covers uses System.currentTimeMillis(). There are a couple of solutions to this. You can disable the auto-timestamping and define your own beforeInsert event which enables you to use DateTimeUtils.setCurrentMillisFixed. For example:

static mapping = {
autoTimestamp false
}

def beforeInsert = {
dateCreated = new DateTime()
}

The other option would be to mock out the value returned by System.currentTimeMillis(). 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.

On a related note the next release of the Joda-Time plugin will bind additional methods to DateTimeUtils to scope mocking of the current timestamp, for example:

DateTimeUtils.withCurrentMillisFixed(aLong) {
// do some stuff that requires a mocked current time
}

No more forgetting to call DateTimeUtils.setCurrentMillisSystem() in your tearDown method!

3 Mar 2009

Persisting DateTime with zone information

I was stuck a while ago trying to figure out how to map PersistentDateTimeTZ in a GORM class. It's an implementation of Hibernate's UserType interface that persists a Joda DateTime value using 2 columns - one for the actual timestamp and one for the time zone. The DateTime 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 java.util.Date values).

I could never figure out how to map the user type to my domain class property correctly. Just doing:

static mapping = {
dateTimeProperty type: PersistentDateTimeTZ
}

Failed with:

org.hibernate.MappingException: property mapping has wrong number of columns.

I seem to remember someone on the Grails mailing list suggesting I tried treating the value as an embedded type. That also didn't work as GORM embedded types have to be Groovy classes in grails-app/domain and PersistentDateTimeTZ is written in Java and lives in a library jar.

I finally found the solution in the 2nd Edition of The Definitive Guide to Grails (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:

static mapping = {
dateTimeProperty type: PersistentDateTimeTZ, {
column name: "date_time_property_timestamp"
column name: "date_time_property_zone"
}
}

The order of the columns corresponds to the order of the values returned by the sqlTypes() method of whatever UserType implementation you're using.

2 Mar 2009

Why would I ever want to disable the L2 cache?

This question came up when pairing last week. We were going through our code-base adding the cache directive 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 DataSource.groovy but not actually used unless cache(true) 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?

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ï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.

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 ehcache use time-based and LRU eviction).

Oh, and yeah, we did have some issues with our changes but most seem to be to do with cruft and tech debt in our code (mostly now-redundant workarounds to GORM issues from older releases of Grails).

1 Mar 2009

Hibernate POGOs, Immutability and Encapsulation

I had a confusing experience this morning. I'm working on a simple web based game as a learning exercise.

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).

  <g:isNextPlayer>
<!-- display something only active player should see -->
</g:isNextPlayer>

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.

The tag uses a transient property on the Game domain class that looks like this:

  Player getNextPlayer() {
return players.empty ? null : players[turn % players.size()]
}

The variable turn is simply an integer that gets incremented when a turn completes.

After poking around with debug logging I figured out that the implementation of getNextPlayer was fine and the value of turn wasn't being accidentally changed but the collection property players was getting re-ordered. What I'd done was introduce some code mid-way in the page that displays the players' names and scores - ordered by score.

  <g:each var="player" in="${gameInstance.players.sort { -it.score }}">
<tr>
<td>${player.user.username}</td>
<td>${player.score}</td>
</tr>
</g:each>

I had assumed when I did this that Collection.sort(Closure) would return a copy (which is 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 List. On List instances the method acts as a mutator and does an in-place sort.

  def c = [1,2,3] as Set
def s = c.sort { it }
assert !(c.is(s))

Remove the 'as Set' and the assertion fails.

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 players property of Game. 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 Player can change - his score can change, for example, but not the collection property of Game. In a regular non-persistent class this sort of invariant would be enforced by overriding the getter and setter:

  private List players
List getPlayers() { players.asImmutable() }
void setPlayers(List players) {
this.players = []
this.players.addAll players
}

If my Game class was implemented that way I'd have got an UnsupportedOperationException from the sort call. If nothing else it would have saved me 5 minutes of "WTF?" 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 private will result in a compilation failure - 'The field 'players' is declared multiple times.' Declaring the property without private gets you past the compilation phase but Grails 'addTo*' dynamic method isn't bound.

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 anæmic domain model anti-pattern even to the extent of a design something like the cautionary tale of POTS. 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.