Reputation: 358
I'm using Groovy 2.4.3 inside of a Grails web application. I have the following Trait/Class hierarchy declared in it:
trait GuidData {
String Guid
}
class Enrollment implements GuidData {
String email
}
When I execute the following code I get the expected results:
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
But when I execute the method:
Enrollment.getDeclaredField("guid")
I get a NoSuchFieldException. If I execute a "getDeclaredMethod()" for the "getEmail" method, I correctly get a java.reflect.Method instance back.
So ... it appears that Groovy properties defined in a trait show as Groovy properties and can be referenced like a property defined within the parent class, but they do NOT reflect as a field with getter/setters in the standard Groovy property pattern. In other words, if the property shows up in the instance call to the getProperties(), I would expect the reflection call to get the Field definition to work as well.
Upvotes: 1
Views: 1463
Reputation: 1846
From the Groovy documentation on Traits, specifically on public fields (as Burt noted below, this also applies to properties):
…in order to avoid the diamond problem, field names are remapped in the implementing class…
It goes on:
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
.
So for the Enrollment
class that implements GuidData
, it doesn't have a field named Guid
, it has a field named GuidData__Guid
(assuming Enrollment
is not in a package). That's why you're experiencing the NoSuchFieldException
. This should work:
Enrollment.getDeclaredField("GuidData__Guid")
The Enrollment
class does have getters/setters String getGuid()
, void setGuid(String arg1)
, and that's how you are able to access it using the regular property accessor or using the regular getter syntax.
Upvotes: 3