如何将对象上的元类恢复为原始类定义

时间:2015-01-14 17:25:34

标签: groovy metaprogramming

我一直试图在新对象上创建TEMPORARY覆盖,然后删除对象本身的覆盖。我不确定是否可以这样做,但这是我迄今为止尝试过的。

// Say I have a class like:
class Validator {
  boolean validate() { println "code here to return actual true/false"; false }
}

// I have two integration points one of them is Here before construction:

// First integration point:
// Save actual validate function
def realValidate = Validator.&validate
// Make new instances of Validator have the validate function hardwired to true
Validator.metaClass.validate { -> println "hardwired true"; true }

// Code I'd rather not modify
// Now some code executes which news up an instance and calls validate
def validator = new Validator()
validator.validate() // This correctly calls our override

// Second integration point.
// Without newing up a new Validator object, I'd like to remove the override.
Validator.metaClass = null

validator.metaClass.validate = Validator.&validate

// This throws "java.lang.IllegalArgumentException: object is not an instance of declaring class"
//validator.validate()

// So maybe I have to explicitly say:
realValidate.resolveStrategy = Closure.DELEGATE_FIRST

// But this still throws the same exception
//validator.validate()

// Perhaps if I tell my objects metaclass to forget about validate, it will bubble up and look for the method on its declaring class?
validator.metaClass.validate = { -> throw new MissingMethodException("validate", Validator.class, (Object[])[], false) }

// This throws MissingMethodException: No signature of method: Validator.validate() is applicable for argument types: () values: []
//  Possible solutions: validate(), wait()
//validator.validate()

抱歉没有超级具体的问题,因为我不知道在这个特定领域有什么可能。我既喜欢我的代码不起作用的原因,也喜欢使其成功的替代方案。

2 个答案:

答案 0 :(得分:0)

对您的策略进行一些小修改将是富有成效的。在对象上使用metaClass而不是Class。

// Say I have a class like:
class Validator {
  boolean validate() { println "code here to return actual true/false"; false }
}

def validator = new Validator()

// mark that the pointer is on object instead of class
def realValidate = validator.&validate

validator.metaClass.validate { -> println "hardwired true"; true }
validator.validate() // This correctly calls our override

// Second integration point.
// DO NOT NEED THIS
// validator.metaClass = null

// Assign the method pointer to validate to call original validate
validator.metaClass.validate = realValidate

validator.validate()

您的方法无效,因为您在类引用的validate()上覆盖metaClass而不是对象本身。

答案 1 :(得分:0)

这可能是每个实例的元类问题... Validator.metaClass = null会将Validator类的全局元类设置为默认值。但是这里的验证器实例是一个Groovy类,因此在实例本身中存储了对元类的单独引用。使用该实例的调用将不会查找全局元类,而是使用每个实例元类(存储在实例本身中的引用)。因此,validator.metaClass = null是重置此

的唯一方法