如何从methodMissing,Groovy元编程中获取被调用方关闭的名称

时间:2018-10-15 10:44:26

标签: 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
    }
} 

在重写的方法中,我无法识别被调用方关闭的字段名称,在这种情况下,即元数据1,元数据2。在Groovy中,有什么方法可以从调用位置获取被调用方关闭名称以进行标识?

1 个答案:

答案 0 :(得分:1)

没有诸如调用方关闭名称之类的东西。在您的示例中,在方法setup(fieldName)中搜索一个存储为类字段的闭包,找到闭包后,您将使用metaFieldVal()执行该闭包。字段名称metadata1与以metaFieldVal()执行的闭包之间没有连接。实际上,setup(fieldName)知道此闭包存储为类字段,但是闭包本身并不知道它。

如果要在metadata1内获取metadata2methodMissing()字段名称,则只需将其作为此不存在的方法参数传递即可。像这样:

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]]

因为闭包没有名字。