【问题标题】:Dynamic direct field access in Groovy?Groovy 中的动态直接字段访问?
【发布时间】:2020-06-03 15:37:45
【问题描述】:

XmlSlurper 的解析对象直接字段访问 (groovy.xml.slurpersupport.NodeChild.@someAttributeName) 是如何工作的?考虑一个输入文件foobar.xml

<root foo="bar">
    <foobar>Hi</foobar>
</root>

和 Groovy 脚本:

import groovy.xml.XmlSlurper

def xml = new XmlSlurper().parse new File('./foobar.xml')

println xml.foobar
println xml.@foo

输出:

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 的字段.如果对上述问题存在任何固有的误解,请告诉我。

【问题讨论】:

    标签: groovy dynamic metaprogramming


    【解决方案1】:

    所以,你可以去看看Nodeover here的源代码

    神奇之处在于lines 55-58 上的静态初始化块,它使用一个新的元类调用 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 之上,谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-01
    • 1970-01-01
    • 2011-05-11
    相关资源
    最近更新 更多