Groovy – Simplest way of resolving a nested property

July 24, 2013 at 09:00

So let’s say that in Groovy you find yourself wanting to do something like this:

[ 'name', 'lastName', 'address.street'].collect { propertyToResolve ->
   [(propertyToResolve): user[property]
}

You will find that the automatic getter (using it with the map syntax or as a property doesn’t change anything) won’t parse the argument to resolve the property in the whole object graph, but it will just search for a property in the object where is called (which absolutely make sense, of course 😀 ).

The next piece of code is one that I like to have in my typical grailsUtils bean:

def resolveNestedProperty(bean, String nestedProperty) {
   nestedProperty.tokenize('.').inject(bean) { valueSoFar, property -> 
      valueSoFar[property] 
   }
}

Then you will be able to resolve the previous example by doing:

[ 'name', 'lastName', 'address.street'].collect { propertyToResolve ->
   [(propertyToResolve): grailsUtils.resolveNestedProperty(property, user) 
}

Yes, yes, I know: nothing really fancy or new, but it came in handy many times and I wanted to write it down 😀 .

Update: I updated the method in order to be more powerful (using Eval) yet faster when possible (by detecting if the expression needs Eval or not using regular expressions). So now it looks like the following:

   static resolveNestedProperty(bean, String nestedProperty) {
      nestedProperty ==~ /[a-zA-Z0-9]+/ ? bean[nestedProperty] :
      nestedProperty ==~ /[a-zA-Z0-9.]+/ ? nestedProperty.tokenize('.').inject(bean) { 
         valueSoFar, property -> valueSoFar ? valueSoFar[property] : null
      } : Eval.me('bean', bean, "bean.${nestedProperty}")
   }