2

folks! I want to be able to navigate Groovy object graph dynamically, having the path in string:

def person = new Person("john", new Address("main", new Zipcode("10001", "1234")))
def path = 'address.zip.basic'

I know that I can access a property in map notation, but it's only one level deep:

def path = 'address'
assert person[path] == address

Is there any way to evaluate deeper path?

Thanks!

JBaruch
  • 22,610
  • 5
  • 62
  • 90
  • possible duplicate of [how to retrieve nested properties in groovy](http://stackoverflow.com/questions/5488689/how-to-retrieve-nested-properties-in-groovy) – Dónal Apr 07 '11 at 08:55

1 Answers1

1

This can be achieved by overriding the getAt operator and traversing the property graph. The following code uses Groovy Category but inheritance or mixins could also be used.

class ZipCode {
    String basic
    String segment

    ZipCode(basic, segment) {
        this.basic = basic
        this.segment = segment
    }
}

class Address {
    String name
    ZipCode zip

    Address(String name, ZipCode zip) {
        this.name = name
        this.zip = zip
    }
}

class Person {
    String name
    Address address

    Person(String name, Address address) {
        this.name = name
        this.address = address
    }

}

@Category(Object)
class PropertyPath {

    static String SEPARATOR = '.'

    def getAt(String path) {

        if (!path.contains(SEPARATOR)) {
            return this."${path}"
        }

        def firstPropName = path[0..path.indexOf(SEPARATOR) - 1]
        def remainingPath = path[path.indexOf(SEPARATOR) + 1 .. -1]
        def firstProperty = this."${firstPropName}"
        firstProperty[remainingPath]
    }
}

def person = new Person('john', new Address('main', new ZipCode('10001', '1234')))

use(PropertyPath) {
    assert person['name'] == 'john'
    assert person['address.name'] == 'main'
    assert person['address.zip.basic'] == '10001'
}

PropertyPath.SEPARATOR = '/'
use(PropertyPath) {
    assert person['address/zip/basic'] == '10001'
}
Gergely Toth
  • 6,638
  • 2
  • 38
  • 40