在Groovy in Action,2015年第8.4.5章发布的第2版中,他们说类别可用于添加GroovyObject
方法:
类别方法名称可以采用属性访问器的形式 (假装属性访问),运算符方法和 GroovyObject 方法即可。 MOP钩子方法不能通过类别类添加。 这是Groovy 2.4的限制。该功能可能会成为 可在以后的版本中使用。
我解释为您可以添加getMetaClass()
,setMetaClass(MetaClass)
,getProperty(String)
,setProperty(String, Object)
和invokeMethod(String, Object)
,但不能添加methodMissing(String, Object)
或propertyMissing(String)
但是当我尝试在某个类别中添加invokeMethod()
和getProperty()
时,它没有任何效果:
class MyClass{}
a = new MyClass()
@Category(MyClass)
class MyCategory {
def missingMethod(String name, def args) { "missingMethod" } // GINA says no MOP hook method
def invokeMethod(String name, def args) { "invokeMethod" } // but GroovyObject method should be fine
def getProperty(String name) { "missingProperty" }
def getMyProperty() { "prop1" }
}
use(MyCategory) {
assert "missingMethod" == a.missingMethod('a', 'b') // methods are the
assert "invokeMethod" == a.invokeMethod('a', 'b')
assert "prop1" == a.myProperty
// but they are not in effect
// assert "missingMethod" == a.method1() // MissingMethodException
// assert "invokeMethod" == a.method2() // MssingMethodException
// assert "missingProperty" == a.property // MissingPropertyException
}
到目前为止invokeMethod
,getProperty
和getMetaClass
所以GroovyObject
左侧还有其他两种方法:setMetaClass
和setProperty
但是从那以后这些的getter版本不起作用我怀疑setter版本也不会工作。所以我不能以这种方式添加任何GroovyObject方法。
在另一个SO问题中:get vs getProperty in groovy有一些关于MOP的讨论,唯一的答案是“向元类添加方法而不是使用类别”解决方案。但我的问题不同,是否真的可以使用类别添加invokeMethod
或methodMissing
?
那么通过类别添加GroovyObject
方法的正确方法(如果有的话)是什么?
答案 0 :(得分:0)
当前的Groovy 2.4.x无法做到这一点,但它已添加到2.5.0-rc-3,2.6.0-alpha-4,3.0.0-alpha-3。因此,未来版本的Groovy将允许通过类别类重新定义methodMissing
和propertyMissing
。此功能已于2018年5月在提交ad664b1上添加,并由GROOVY-3867
// since groovy 2.5.0-rc-3
class X{ def bar(){1}}
class XCat{ static bar(X x){2}}
class XCat2{ static bar(X x){3}}
class XCat3{ static methodMissing(X x, String name, args) {4}}
class XCat4{ static propertyMissing(X x, String name) {"works"}}
def x = new X()
shouldFail(MissingPropertyException) {
assert x.baz != "works" // accessing x.baz should throw MPE
}
use(XCat4) {
assert x.baz == "works"
}
shouldFail(MissingPropertyException) {
assert x.baz != "works" // accessing x.baz should throw MPE
}