How to restore metaclass on object to original class definition

删除回忆录丶 提交于 2020-01-17 03:14:08

问题


I've been trying to create a TEMPORARY override on new objects, and then to remove the override on the objects themselves. I'm not sure if this can be done, but here is what I've tried so far.

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

Apologies for not having a super specific question, since I don't know what all is possible in this particular area. I'd love both the reason why my code doesn't work, as well as alternatives to make it work.


回答1:


This could be a per instance meta class problem... Validator.metaClass = null will set the global meta class for the Validator class to default. but your validator instance here is a Groovy class and thus stores a separate reference to the meta class in the instance itself. Calls with that instance will not go through a lookup of the global meta class and instead use the per instance meta class (the reference stored in the instance itself). Thus validator.metaClass = null is the only way to reset this




回答2:


A small modification to your strategy would be fruitful. Use metaClass on the object instead of the 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()

Your approach did not work because you had validate() overridden on the metaClass of Class reference instead of the object itself.



来源:https://stackoverflow.com/questions/27948841/how-to-restore-metaclass-on-object-to-original-class-definition

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!