11

I'm wondering what is the best way to retrieve nested properties in Groovy, taking a given Object and arbitrary "property" String. I would like to something like this:

someGroovyObject.getProperty("property1.property2")

I've had a hard time finding an example of others wanting to do this, so maybe I'm not understanding some basic Groovy concept. It seems like there must be some elegant way to do this.

As reference, there is a feature in Wicket that is exactly what I'm looking for, called the PropertyResolver: http://wicket.apache.org/apidocs/1.4/org/apache/wicket/util/lang/PropertyResolver.html

Any hints would be appreciated!

4

4 回答 4

25

我不知道 Groovy 是否有内置的方法来做到这一点,但这里有 2 个解决方案。在Groovy 控制台中运行此代码以对其进行测试。

def getProperty(object, String property) {

  property.tokenize('.').inject object, {obj, prop ->       
    obj[prop]
  }  
}

// Define some classes to use in the test
class Name {
  String first
  String second
}

class Person {
  Name name
}

// Create an object to use in the test
Person person = new Person(name: new Name(first: 'Joe', second: 'Bloggs'))

// Run the test
assert 'Joe' == getProperty(person, 'name.first')

/////////////////////////////////////////
// Alternative Implementation
/////////////////////////////////////////
def evalProperty(object, String property) {
  Eval.x(object, 'x.' + property)
}

// Test the alternative implementation
assert 'Bloggs' == evalProperty(person, 'name.second')
于 2011-03-30T16:14:02.540 回答
3

Groovy Beans让您可以直接访问字段。您不必定义 getter/setter 方法。它们是为您生成的。每当您访问 bean 属性时,都会在内部调用 getter/setter 方法。您可以使用 .@ 运算符绕过此行为。请参见以下示例:

class Person {
    String name
    Address address
    List<Account> accounts = []
}

class Address {
    String street
    Integer zip
}

class Account {
    String bankName
    Long balance
}

def person = new Person(name: 'Richardson Heights', address: new Address(street: 'Baker Street', zip: 22222)) 
person.accounts << new Account(bankName: 'BOA', balance: 450)
person.accounts << new Account(bankName: 'CitiBank', balance: 300)

如果您不处理集合,您只需调用您要访问的字段即可。

assert 'Richardson Heights' == person.name
assert 'Baker Street' == person.address.street
assert 22222 == person.address.zip

如果要访问集合中的字段,则必须选择元素:

assert 'BOA' == person.accounts[0].bankName
assert 300 == person.accounts[1].balance​​​​​​​​​
于 2011-03-30T16:54:56.877 回答
1

您也可以使用propertyMissing. 这就是你可能称之为 Groovy 的内置方法的东西。

在你的课堂上声明:

def propertyMissing(String name) {
    if (name.contains(".")) {
        def (String propertyname, String subproperty) = name.tokenize(".")
        if (this.hasProperty(propertyname) && this."$propertyname".hasProperty(subproperty)) {
            return this."$propertyname"."$subproperty"
        }
    }
}

然后根据需要参考您的属性:

def properties = "property1.property2"
assert someGroovyObject."$properties" == someValue

这是自动递归的,您不必显式调用方法。这只是一个 getter,但您也可以使用参数定义第二个版本来创建一个 setter。

缺点是,据我所知,您只能定义 的一个版本propertyMissing,因此您必须决定是否要使用动态路径导航。

于 2014-11-11T23:10:36.937 回答
0

https://stackoverflow.com/a/15632027/2015517

它使用可用作 GString 一部分的 ${} 语法

于 2013-03-26T11:40:30.300 回答