[英]Dynamic direct field access in Groovy?
How does something like XmlSlurper
's parsed objects direct field access ( groovy.xml.slurpersupport.NodeChild.@someAttributeName
) work? XmlSlurper
的解析对象直接字段访问( groovy.xml.slurpersupport.NodeChild.@someAttributeName
)如何工作? Consider an input file foobar.xml
:考虑一个输入文件
foobar.xml
:
<root foo="bar">
<foobar>Hi</foobar>
</root>
and the Groovy script:和 Groovy 脚本:
import groovy.xml.XmlSlurper
def xml = new XmlSlurper().parse new File('./foobar.xml')
println xml.foobar
println xml.@foo
Outputs:输出:
Hi
bar
As far as I understand, xml.foobar
(a nonexistent property) can be handled by using the metaprogramming method propertyMissing()
(similar to the methodMissing()
for nonexistent methods).据我了解,可以使用元编程方法
propertyMissing()
处理xml.foobar
(不存在的属性)(类似于不存在方法的methodMissing()
)。 However, I can't seem to find a dynamic analog for direct access fields like foo
.但是,我似乎找不到像
foo
这样的直接访问字段的动态模拟。 How could I implement something similar?我怎么能实现类似的东西? Ie, I could create a class that dynamically handles property/method accesses (eg, along with a backing map) and the metaprogramming methods above, but there doesn't seem to be the equivalent for fields, eg:
即,我可以创建一个 class 动态处理属性/方法访问(例如,连同支持映射)和上面的元编程方法,但似乎没有字段的等价物,例如:
class DynamicTest {
def propertyMissing(String propertyName) {
println "Hit missing property $propertyName"
}
def methodMissing(String methodName, def args) {
println "Hit missing method $methodName"
}
// nothing like this exists?
def fieldMissing(String fieldName) {
println 'Hit missing field $fieldName'
}
}
def obj = new DynamicTest()
obj.test1() // Hit missing method test1
obj.test2 // Hit missing property test2
obj.@test3 // Caught: groovy.lang.MissingFieldException: No such field: test3 for class: DynamicTest
Note that I have a day's worth of experience with Groovy and metaprogramming, so I'm not too sure if I'm using the correct language here.请注意,我在 Groovy 和元编程方面有一天的经验,所以我不太确定我是否在这里使用了正确的语言。 My understanding that
xml.foobar
is a Groovy-type metaprogramming "field" (which can be also be accessed using xml.getProperty('foobar')
, xml['foobar']
, and xml.getAt('foobar')
), and that xml.@foo
is an ordinary, Java-like field. My understanding that
xml.foobar
is a Groovy-type metaprogramming "field" (which can be also be accessed using xml.getProperty('foobar')
, xml['foobar']
, and xml.getAt('foobar')
),并且xml.@foo
是一个普通的类似 Java 的字段。 Please let me know if there are any inherent misconceptions with the question above.请让我知道上述问题是否存在任何固有的误解。
So, you can go and have a look at the source code for Node
over here因此,您可以 go 并在此处查看
Node
的源代码
The magic is in the static initializer block on lines 55-58 , which calls setMetaclass with a new metaclass that catches attribute getting and setting神奇之处在于第55-58 行的 static 初始化程序块,它使用新的元类调用 setMetaclass,该元类捕获属性获取和设置
Converting to Groovy you end up with something like this:转换为 Groovy 你最终会得到这样的结果:
class Example {
static {
setMetaClass(GroovySystem.metaClassRegistry.getMetaClass(Example), Example)
}
def get(name) {
println "Getting $name"
}
def set(name, value) {
println "Setting $name to $value"
}
protected static void setMetaClass(final MetaClass metaClass, Class nodeClass) {
final MetaClass newMetaClass = new DelegatingMetaClass(metaClass) {
@Override
def getAttribute(object, String attribute) {
object.get("@$attribute")
}
@Override
void setAttribute(object, String attribute, newValue) {
object.set("@$attribute", newValue)
}
};
GroovySystem.metaClassRegistry.setMetaClass(nodeClass, newMetaClass);
}
}
def e = new Example()
e.@woo // prints "Getting @woo"
e.@woo = 'yay' // prints "Setting @woo to yay"
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.