1

I have a class that extends Expando and gets injected with dynamic properties.

class Dynamo extends Expando {
}

Dynamo dynamic = [ firstName: 'bob', lastName: 'dobbs' ]

I'd like to create a dynamic property fullName that evaluates to "$lastName, $firstName".

While it sort of does work to do this:

dynamic.fullName = { "$lastName, $fullName" }

It requires an call() or implicit call with () to return the string, otherwise it just gives the closure toString()

assert dynamic.fullName() == 'dobbs, bob'

Passes

But

assert dynamic.fullName == 'dobbs, bob'

Fails because that evaluates to the toString of the closure

I can always do this

Dynamo dynamic = [ firstName: 'bob', lastName: 'dobbs', fullName: 'dobbs, bob' ]

But that ain't DRY...

durp
  • 198
  • 1
  • 6

1 Answers1

1

For parameterless methods, Groovy needs parenthesis. I can think of two solutions:

Solution 1: Metaclass the getter getFullName:

Dynamo dynamo = [ firstName: 'bob', lastName: 'dobbs' ]

dynamo.metaClass.getFullName = { "$lastName, $firstName" }

assert dynamo.fullName == 'dobbs, bob'

Solution 2: Hook into the property getters with getProperty:

Dynamo dyn2 = [ firstName: 'john', lastName: 'doe' ]
dyn2.metaClass.getProperty = { String property ->
    if (property == "fullName") { 
        "${delegate.lastName}, ${delegate.firstName}" 
    } 
}

assert dyn2.fullName == 'doe, john'
Will
  • 14,348
  • 1
  • 42
  • 44
  • I thought I'd run into an issue with the metaclassing when another Dynamo has a "fullName" defined a true property. `Dynamo dyn3 = [ fullName: 'Anonymous' ]` but the Expando resolves the mapped property before the metaclassed getFullName so it's **all good** -> Still wonder if there is way to do this with a lazy eval GString that could be just another attribute, but this might work just fine. – durp Apr 17 '13 at 05:42