2016-05-04 81 views
0

我在Grails Web應用程序中使用Groovy 2.4.3。我有以下特質/類層次結構在它宣稱:如何獲得從Groovy特徵繼承的屬性的java.reflect.Field值?

trait GuidData { 
    String Guid 
} 

class Enrollment implements GuidData { 
    String email 
} 

當我執行下面的代碼我得到預期的結果:

Enrollment enrollment = new Enrollment(email: "[email protected]", guid: "XXXX") 
assert enrollment.properties == ['email':'[email protected]', 'guid':'XXXX'] 
assert enrollment.getProperty("guid") == "XXXX") 
Enrollment.getDeclaredField("email") == private java.lang.String Enrollment.email 

但是,當我執行方法:

Enrollment.getDeclaredField("guid") 

我得到一個NoSuchFieldException。如果我爲「getEmail」方法執行「getDeclaredMethod()」,我會正確地返回一個java.reflect.Method實例。

因此...... Groovy在trait中定義的屬性顯示爲Groovy屬性,並且可以像父類中定義的屬性一樣引用,但它們並不反映爲標準Groovy中具有getter/setter的字段屬性模式。換句話說,如果在調用getProperties()的實例中顯示屬性,我希望反射調用也可以使字段定義正常工作。

+0

你的意思是'Enrollment.getDeclaredField(「guid」)拋出一個'NoSuchFieldException'? – dpcasady

+0

是的。 Enrollment.getDeclaredField(「guid」)引發NoSuchFieldException。 –

回答

3

Groovy documentation on Traits,特別是在公共領域(如伯特下面指出的,這也適用於屬性):

...爲了避免diamond problem,字段名在實現類重新映射...

它接着說:

字段的名稱取決於性狀的全名。包中的所有點(。)都用下劃線(_)替換,最終名稱包含雙下劃線。因此,如果字段的類型是String,則包的名稱是my.package,特徵的名稱是Foo,字段的名稱是bar,在實現類中,公用字段將顯示爲:String my_package_Foo__bar

所以對於Enrollment類實現GuidData,它並沒有一個名爲Guid領域,它有一個名爲GuidData__Guid場(假設Enrollment不在包)。這就是爲什麼你遇到了NoSuchFieldException。這應該工作:

Enrollment.getDeclaredField("GuidData__Guid") 

Enrollment類確實有getter/setter方法String getGuid()void setGuid(String arg1),這就是你如何能夠使用常規屬性訪問或使用常規的getter語法它來訪問。

+0

這不是一個公共領域,它是一個財產。但是屬性的字段(例如'String foo')和已聲明的公共字段(例如'public String foo')類似地被重命名爲 –

+0

Duh。我的壞,謝謝澄清@BurtBeckwith – dpcasady

+0

好吧......這是合理的和有效的。當使用反射爲一個對象中的所有字段獲取數據類型時,這會產生一個有趣的難題,那就是你不需要知道它所操作的類/特徵層次結構的知識。我想你必須迭代一組特徵/接口基類實現併合成每個查找名稱以獲得Field定義。如果你有多重繼承,那麼我想知道你是如何知道哪一個綁定到在實現類上顯示properties()方法的屬性名稱的? –