Я пытаюсь переопределить метод, определенный в Groovy пользовательском Script
классе, переопределив метод через metaClass
объекта, однако изменение полностью игнорируется, и оригинальный метод вызывается как есть. Я попробовал то же самое в обычном классе, и это сработало, как и ожидалось, поэтому мне интересно, что отличается в случае пользовательского Script
. Вот фрагмент, который я сохранил как `/tmp/t.groovy:
class Worker {
def init() {
throw new Exception('I always fail')
}
void start() {
init()
println('I never get to work')
}
}
def worker = new Worker()
worker.metaClass.init = { println("dummy init") }
worker.start()
def shell = new GroovyShell()
def script = shell.parse('@groovy.transform.BaseScript TestScript _')
script.metaClass.init = { println("dummy init") }
script.start()
Где класс TestScript
должен быть определен в своем собственном файле для GroovyShell
, чтобы найти его, поэтому /tmp/TestScript.groovy
имеет класс:
abstract class TestScript extends Script {
def init() {
throw new Exception('I always fail')
}
void start() {
init()
println('I never get to work')
}
}
Вот вывод, когда я бежал, используя Groovy 2.4.14 на Ма c ОС:
$ groovy /tmp/t.groovy
dummy init
I never get to work
Caught: java.lang.Exception: I always fail
java.lang.Exception: I always fail
at TestScript.init(TestScript.groovy:3)
at TestScript.start(TestScript.groovy:7)
at TestScript$start.call(Unknown Source)
at t.run(t.groovy:19)
Вы можете видеть, что изменение, внесенное в worker.metaClass
, было эффективным, но то же самое, что было сделано в script.metaClass
, было проигнорировано. Сначала я попытался отследить вызовы в рабочем сценарии, используя что-то вроде этого:
def worker = new Worker()
def m = new DelegatingMetaClass(worker.metaClass) {
Object invokeMethod(Object object, String methodName, Object[] args) {
println("invokeMethod ${methodName}(${args})")
return super.invokeMethod(object, methodName, args)
}
}
m.initialize()
worker.metaClass = m
worker.start()
Вывод выглядит так:
invokeMethod start([])
invokeMethod init([])
Caught: java.lang.Exception: I always fail
java.lang.Exception: I always fail
...
Вы можете видеть, что и start
, и init
войти в систему. Когда я попробовал то же самое на объекте сценария:
def shell = new GroovyShell()
def script = shell.parse('@groovy.transform.BaseScript TestScript _')
def m = new DelegatingMetaClass(script.metaClass) {
Object invokeMethod(Object object, String methodName, Object[] args) {
println("invokeMethod ${methodName}(${args})")
return super.invokeMethod(object, methodName, args)
}
}
m.initialize()
script.metaClass = m
script.start()
Вывод выглядит так:
invokeMethod start([])
Caught: java.lang.Exception: I always fail
java.lang.Exception: I always fail
...
Вы видите, что вызов init
никогда не делегируется invokeMethod
, Что мне здесь не хватает?