2011-03-30 69 views
8

我想知道什麼是最好的方式來檢索Groovy中的嵌套屬性,採取給定的對象和任意「屬性」字符串。我想是這樣的:如何檢索Groovy中的嵌套屬性

someGroovyObject.getProperty("property1.property2") 

我已經很難找到其他人想要做到這一點的例子,所以也許我不理解一些基本的Groovy概念。似乎必須有一些優雅的方式來做到這一點。

爲參照,有在檢票功能,這正是我要找的,叫PropertyResolver: http://wicket.apache.org/apidocs/1.4/org/apache/wicket/util/lang/PropertyResolver.html

任何提示,將不勝感激!

回答

22

我不知道Groovy是否有內置的方式來做到這一點,但這裏有2個解決方案。在Groovy Console中運行此代碼以對其進行測試。

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') 
+0

這或多或少是我現在正在做的,但你的方式更清潔! – 2011-03-30 17:03:14

+0

對不起,唐,早就應該接受你的回答(當我不知道我在這個網站上做了什麼)。謝謝... – 2013-03-26 16:33:32

+0

注意:我測試了這些,Eval比我的系統上的標記版本慢得多。 – 2017-05-24 00:23:21

2

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​​​​​​​​​ 
+1

這是很好的建議,但我希望能夠接受一個字符串。有沒有辦法強制_person。「address.street」_返回_person.address.street_的值? – 2011-03-30 17:04:59

+0

你可以使用[Groovy的動態方法調用](http://groovy.codehaus.org/Dynamic+Groovy)。但是,它要求您聲明方法名稱:person。「getAddress」()。「getStreet」()。 – 2011-03-30 17:25:49

+0

感謝您的信息和鏈接...我會閱讀它,看看它是否可以幫助這裏。 – 2011-03-30 17:37:36

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,所以你必須決定是否動態路徑導航是你想要使用它。