Groovy 如何将对象上的元类还原为原始类定义

Groovy 如何将对象上的元类还原为原始类定义,groovy,metaprogramming,Groovy,Metaprogramming,我一直在尝试在新对象上创建临时替代,然后删除对象本身的替代。我不确定这是否可以做到,但以下是我迄今为止所做的尝试 // 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 cons

我一直在尝试在新对象上创建临时替代,然后删除对象本身的替代。我不确定这是否可以做到,但以下是我迄今为止所做的尝试

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

很抱歉没有提出一个非常具体的问题,因为我不知道在这个特定领域有什么可能。我喜欢我的代码不起作用的原因,以及使它起作用的替代方案。

对您的策略进行一个小的修改将是富有成效的。对对象而不是类使用
元类

// 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()
,而不是对象本身。

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

AFAIK的唯一方法,在Grails单元/集成测试的上下文中,只需将
元类
设置为null,就可以恢复原始元类,这样做有效吗?@Dónal设置
validator
(类)的元类会使任何新对象都没有覆盖,但在我的例子中,我正在处理一个已经构建的实例。将
验证程序的元类设置为
(对象)没有任何作用。啊,我错了,将元类设置为null确实有效,尽管您必须将类的元类和对象的元类都设置为null。我尝试了每一种,但单独使用它们不起作用,但设置它们两种都起作用!感谢@DónalYes的启发,我已经尝试过这个方法,这确实会起作用,但是在我的例子中,验证器的构建很复杂(不使用DI),所以我在第一个集成点没有对对象的引用。这不重要。它可以尽可能地懒散地完成。您将在某个时间点获得validator对象,在该时间点上,您可以在
newvalidator()之后立即执行答案中显示的任何操作。我不确定我是否理解了其他情况。事实上,验证器接收对多个对象的引用,这些对象还不可用,创建成本很高,并且在构造函数中会产生令人讨厌的副作用。