在 Groovy 的 NodeChild 上添加动态方法的奇怪行为
Strange behaviour of adding dynamic methods on Groovy's NodeChild
我正在使用 Grails XML Parser 来解析 XML 字符串,在获得解析的 NodeChild
实例后,我在该实例上添加动态方法,如下所示:
import grails.converters.XML
import groovy.util.slurpersupport.NodeChild
NodeChild result = XML.parse("<root></root>")
result.getMetaClass().methodA = { return "a" }
result.getMetaClass().methodB = { return "b" }
println rootNode.methodA()
println rootNode.methodB()
现在我调用 methodA()
并期望打印 "a" 的行,我得到 MissingMethodException
找不到 methodA()
。
我对此进行了一段时间的调查,发现所有动态方法都被我们添加的最后一个动态方法所取代,即在这种情况下:methodB()
正在取代(或做某事)methodA()
,所以我先调用 & print methodB()
,它会正确打印 "b"。
这让我想到另一个测试如下:
import grails.converters.XML
import groovy.util.slurpersupport.NodeChild
String result = "any-other-data-type-instance-here-to-inject-dynamic-methods"
result.getMetaClass().methodA = { return "a" }
result.getMetaClass().methodB = { return "b" }
println rootNode.methodA()
println rootNode.methodB()
在这种情况下,两条语句都可以正常打印。所以问题只出在类NodeChild
上。我使用 exando 元类功能很长时间了,我遇到了这样的问题。知道为什么会这样吗?
您需要在返回实例之前分配 metaclass 方法,否则它将具有旧的 metaclass 而不是具有新方法的新方法。此外,分配给 class,而不是实例 - 我不确定您是否只想影响此实例的元 class,但这不是语法。
这个有效:
import grails.converters.XML
import groovy.util.slurpersupport.NodeChild
NodeChild.metaClass.methodA = { return "a" }
NodeChild.metaClass.methodB = { return "b" }
NodeChild result = XML.parse("<root></root>")
println result.methodA()
println result.methodB()
请注意,您使用隐式 it
参数定义方法,但不传递任何内容,因此 Groovy 传递空值。如果您打算让方法没有参数,请使用此语法:
NodeChild.metaClass.methodA = { -> return "a" }
NodeChild.metaClass.methodB = { -> return "b" }
我正在使用 Grails XML Parser 来解析 XML 字符串,在获得解析的 NodeChild
实例后,我在该实例上添加动态方法,如下所示:
import grails.converters.XML
import groovy.util.slurpersupport.NodeChild
NodeChild result = XML.parse("<root></root>")
result.getMetaClass().methodA = { return "a" }
result.getMetaClass().methodB = { return "b" }
println rootNode.methodA()
println rootNode.methodB()
现在我调用 methodA()
并期望打印 "a" 的行,我得到 MissingMethodException
找不到 methodA()
。
我对此进行了一段时间的调查,发现所有动态方法都被我们添加的最后一个动态方法所取代,即在这种情况下:methodB()
正在取代(或做某事)methodA()
,所以我先调用 & print methodB()
,它会正确打印 "b"。
这让我想到另一个测试如下:
import grails.converters.XML
import groovy.util.slurpersupport.NodeChild
String result = "any-other-data-type-instance-here-to-inject-dynamic-methods"
result.getMetaClass().methodA = { return "a" }
result.getMetaClass().methodB = { return "b" }
println rootNode.methodA()
println rootNode.methodB()
在这种情况下,两条语句都可以正常打印。所以问题只出在类NodeChild
上。我使用 exando 元类功能很长时间了,我遇到了这样的问题。知道为什么会这样吗?
您需要在返回实例之前分配 metaclass 方法,否则它将具有旧的 metaclass 而不是具有新方法的新方法。此外,分配给 class,而不是实例 - 我不确定您是否只想影响此实例的元 class,但这不是语法。
这个有效:
import grails.converters.XML
import groovy.util.slurpersupport.NodeChild
NodeChild.metaClass.methodA = { return "a" }
NodeChild.metaClass.methodB = { return "b" }
NodeChild result = XML.parse("<root></root>")
println result.methodA()
println result.methodB()
请注意,您使用隐式 it
参数定义方法,但不传递任何内容,因此 Groovy 传递空值。如果您打算让方法没有参数,请使用此语法:
NodeChild.metaClass.methodA = { -> return "a" }
NodeChild.metaClass.methodB = { -> return "b" }