Groovy中的动态直接字段访问?

Groovy中的动态直接字段访问?,groovy,dynamic,metaprogramming,Groovy,Dynamic,Metaprogramming,像XmlSlurper的解析对象直接访问字段(groovy.xml.slurpersupport.NodeChild.@someAttributeName)是如何工作的?考虑输入文件 FoBAUR.XML: <root foo="bar"> <foobar>Hi</foobar> </root> 产出: Hi bar 据我所知,xml.foobar(一个不存在的属性)可以通过使用元编程方法propertyMissing()(类似于不存在

XmlSlurper
的解析对象直接访问字段(
groovy.xml.slurpersupport.NodeChild.@someAttributeName
)是如何工作的?考虑输入文件<代码> FoBAUR.XML<代码>:

<root foo="bar">
    <foobar>Hi</foobar>
</root>
产出:

Hi
bar
据我所知,
xml.foobar
(一个不存在的属性)可以通过使用元编程方法
propertyMissing()
(类似于不存在的方法的
methodMissing()
)来处理。然而,我似乎找不到像
foo
这样的直接访问字段的动态模拟。我如何实现类似的功能?也就是说,我可以创建一个类来动态处理属性/方法访问(例如,连同一个备份映射)和上面的元编程方法,但是对于字段似乎没有等效的方法,例如:

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

注意,我在Groovy和元编程方面有一天的经验,所以我不太确定我在这里是否使用了正确的语言。我的理解是,
xml.foobar
是一个Groovy类型的元编程“字段”(也可以使用
xml.getProperty('foobar')
xml['foobar']
、和
xml.getAt('foobar')
)访问该字段,
xml.@foo
是一个普通的、类似Java的字段。如果对上述问题有任何固有的误解,请告诉我。

因此,您可以去查看
节点的源代码

神奇之处在于上的静态初始值设定项块,它使用捕获属性获取和设置的新元类调用setMetaclass

转换为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"

这是一个很好的例子,说明了Groovy是如何构建在Java之上的,谢谢!
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"