首页 > 解决方案 > 如何从 methodMissing、Groovy 元编程中获取被调用者闭包的名称

问题描述

我正在尝试使用 Groovy 的Meta Programming,从闭包中动态读取数据。下面是示例:

class MyClass {

    static def metadata1 = {
        metadataA(key1: 'value1', key2: "value2")
        metadataB(key1: ['value1', 'value2'], key2: 78978)
    }

    static def metadata2 = {
        metadataA(key1: 'value11', key2: "value21")
        metadataB(key1: ['value11', 'value21'], key2: 78958)
    }

    static void main(def args) {
        new MyClass().setup("metadata1")
        new MyClass().setup("metadata2")
    }

    def setup(fieldName) {
        try {
            Field metaField = this.class.getDeclaredField(fieldName)
            if (metaField != null) {
                metaField.setAccessible(true)
                def metaFieldVal = metaField.get(null)
                if (metaFieldVal != null) {
                    metaFieldVal.delegate = this
                    metaFieldVal() // It will call closure metadata1 or metadata2
                }
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace()
        }
    }

    def methodMissing(String key, args) {
        println(key) // metadataA
        println(args) // [[key1:value1, key2:value2]]

        //println(getNameofCalleeClosure()) //metadata1
    }
} 

在覆盖的 methodMissing 中,我无法识别被调用者闭包的字段名称,以防万一,即 metadata1、metadata2。Groovy 中是否有任何方法可以从调用位置获取被调用者闭包名称以进行识别?

标签: groovy

解决方案


没有像调用者闭包的名称这样的东西。在您的示例中,在方法中setup(fieldName)搜索存储为类字段的闭包,当您找到闭包时,您使用metaFieldVal(). metadata1字段名称和执行为 的闭包之间没有联系metaFieldVal()。实际上这setup(fieldName)知道这个闭包被存储为一个类字段,但是闭包本身并不知道它。

如果你想在里面获取metadata1metadata2字段名称,methodMissing()你必须简单地将它作为这个不存在的方法参数传递。像这样的东西:

class MyClass {

    static def metadata1 = {
        metadataA("metadata1", [key1: 'value1', key2: "value2"])
        metadataB("metadata1", [key1: ['value1', 'value2'], key2: 78978])
    }

    static def metadata2 = {
        metadataA("metadata2", [key1: 'value11', key2: "value21"])
        metadataB("metadata2", [key1: ['value11', 'value21'], key2: 78958])
    }

    static void main(def args) {
        new MyClass().setup("metadata1")
        new MyClass().setup("metadata2")
    }

    def setup(fieldName) {
        try {
            Field metaField = this.class.getDeclaredField(fieldName)
            if (metaField != null) {
                metaField.setAccessible(true)
                def metaFieldVal = metaField.get(null)
                if (metaFieldVal != null) {
                    metaFieldVal.delegate = this
                    metaFieldVal() // It will call closure metadata1 or metadata2
                }
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace()
        }
    }

    def methodMissing(String key, args) {
        println(key) // metadataA
        println(args) // [metadata1, [key1:value1, key2:value2]]

    }
} 

还值得一提的是,像这样执行缺失的方法:

static def metadata1 = {
    metadataA(this, [key1: 'value1', key2: "value2"])
    metadataB(this, [key1: ['value1', 'value2'], key2: 78978])
}

产生:

[class MyClass, [key1:value1, key2:value2]]

并传递这样的字段metadata1

static def metadata1 = {
    metadataA(metadata1, [key1: 'value1', key2: "value2"])
    metadataB(metadata1, [key1: ['value1', 'value2'], key2: 78978])
}

将产生:

[MyClass$__clinit__closure1@50d0686, [key1:value1, key2:value2]]

因为闭包没有名字。


推荐阅读