使用柯里化闭包重写Groovy元类invokeMethod失效问题排查
Groovy柯里化闭包重写invokeMethod失效问题分析
问题根源
Groovy的invokeMethod要求签名为Object invokeMethod(String name, Object args),虽然你柯里化后的闭包参数列表匹配,但柯里化操作没有同步更新闭包内部的方法元数据,导致Groovy元类系统无法识别它符合invokeMethod的签名规则,最终跳过了你的闭包,执行了默认的方法逻辑。
简单说:柯里化只改了参数,没改Groovy内部用来做方法绑定的元信息,元类不认这个闭包是合法的invokeMethod实现。
修复方案
不要直接赋值柯里化闭包,用一个普通闭包包装它的调用,让元类系统能正确识别签名:
// Create closures def invokeClosure1 = { String name, Object args -> name } def invokeClosure2 = { String suffix, String name, Object args -> "${name}$suffix" } def invokeClosure2Curried = invokeClosure2.curry('!') assert invokeClosure2Curried.parameterTypes as List == [String, Object] // Test closures assert invokeClosure1('foo', null) == 'foo' assert invokeClosure2Curried('foo', null) == 'foo!' // Create an object def s = 'Hello' assert s.toUpperCase() == 'HELLO' // Override instance metaclass invokeMethod with a regular closure s.metaClass.invokeMethod = invokeClosure1 assert s.toUpperCase() == 'toUpperCase' // 修正:用普通闭包包装柯里化闭包调用 s.metaClass.invokeMethod = { String name, Object args -> invokeClosure2Curried(name, args) } assert s.toUpperCase() == 'toUpperCase!'
补充说明
你可以打印柯里化闭包的getMetaMethod('call')信息,会发现它的元数据还是关联原闭包的签名,这就是元类系统不识别它的核心原因。用普通闭包包装后,新闭包的元数据完全符合invokeMethod的要求,就能正常生效了。
内容的提问来源于stack exchange,提问作者Dmitry E.
相关产品推荐
相关产品推荐

