如何为从 Groovy 特征继承的 属性 获取 java.reflect.Field 值?

How do I get a java.reflect.Field value for a property inherited from a Groovy trait?

我在 Grails Web 应用程序中使用 Groovy 2.4.3。我在其中声明了以下 Trait/Class 层次结构:

trait GuidData {
    String Guid
}

class Enrollment implements GuidData {
    String email
}

当我执行以下代码时,我得到了预期的结果:

Enrollment enrollment = new Enrollment(email: "joe@tester.com", guid: "XXXX")
assert enrollment.properties == ['email':'joe@tester.com', '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 属性显示为 Groovy 属性并且可以像在父 class 中定义的 属性 一样被引用,但它们不会反映为标准 Groovy 属性 模式中具有 getter/setters 的字段。换句话说,如果 属性 出现在对 getProperties() 的实例调用中,我希望反射调用也能使 Field 定义正常工作。

来自 Groovy documentation on Traits,特别是 public 字段(正如 Burt 在下面指出的,这也适用于属性):

…in order to avoid the diamond problem, field names are remapped in the implementing class…

它继续:

The name of the field depends on the fully qualified name of the trait. All dots (.) in package are replaced with an underscore (_), and the final name includes a double underscore. So if the type of the field is String, the name of the package is my.package, the name of the trait is Foo and the name of the field is bar, in the implementing class, the public field will appear as: String my_package_Foo__bar.

因此对于实现 GuidDataEnrollment class,它没有名为 Guid 的字段,它有一个名为 GuidData__Guid 的字段(假设 Enrollment 不在包中)。这就是您遇到 NoSuchFieldException 的原因。这应该有效:

Enrollment.getDeclaredField("GuidData__Guid")

Enrollment class 确实有 getters/setters String getGuid()void setGuid(String arg1),这就是您可以使用常规 [=37] 访问它的方式=] 访问器或使用常规 getter 语法。