是否可以通过类别添加GroovyObject方法?

时间:2017-12-07 09:16:44

标签: groovy

在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
}

到目前为止invokeMethodgetPropertygetMetaClass所以GroovyObject左侧还有其他两种方法:setMetaClasssetProperty但是从那以后这些的getter版本不起作用我怀疑setter版本也不会工作。所以我不能以这种方式添加任何GroovyObject方法。

在另一个SO问题中:get vs getProperty in groovy有一些关于MOP的讨论,唯一的答案是“向元类添加方法而不是使用类别”解决方案。但我的问题不同,是否真的可以使用类别添加invokeMethodmethodMissing

那么通过类别添加GroovyObject方法的正确方法(如果有的话)是什么?

1 个答案:

答案 0 :(得分:0)

当前的Groovy 2.4.x无法做到这一点,但它已添加到2.5.0-rc-3,2.6.0-alpha-4,3.0.0-alpha-3。因此,未来版本的Groovy将允许通过类别类重新定义methodMissingpropertyMissing。此功能已于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
}