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

How to restore metaclass on object to original class definition

我一直在尝试对新对象创建一个临时覆盖,然后删除对对象本身的覆盖。我不确定这是否可以完成,但这是我到目前为止尝试过的方法。

// 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()

很抱歉没有一个超级具体的问题,因为我不知道在这个特定领域有什么可能。我喜欢我的代码不起作用的原因,也喜欢让它起作用的替代方法。

对您的策略进行小的修改将会卓有成效。在对象上使用 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()

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

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

的唯一方法