Я экспериментирую с созданием динамической переменной с GroovyShell
и столкнулся с проблемой. Во-первых, рабочий код:
static def defVar(def glob) {
glob.setVariable('test', new Test())
}
class MyBinding extends Binding {
}
class Test {
def call() {
println("--- hello ---")
}
}
Binding glob = new MyBinding()
GroovyShell shell = new GroovyShell(glob)
defVar(glob)
shell.parse('test()').run()
Это дает мне ожидаемый результат:
--- hello ---
Однако я хочу динамически вызывать setVariable()
, когда вызывается getVariable()
, что-то вроде этого:
static def defVar(def glob) {
glob.setVariable('test', new Test())
}
class MyBinding extends Binding {
def getVariable(String name) {
if (! hasVariable('test')) {
BindingTest.defVar(this)
}
return super.getVariable(name)
}
}
class Test {
def call() {
println("--- hello ---")
}
}
Binding glob = new MyBinding()
GroovyShell shell = new GroovyShell(glob)
//defVar(glob)
shell.parse('test()').run()
Но это не с приведенной ниже ошибкой:
Caught: groovy.lang.MissingMethodException: No signature of method: Script1.test() is applicable for argument types: () values: []
Possible solutions: getAt(java.lang.String), use([Ljava.lang.Object;), use(java.lang.Class, groovy.lang.Closure), use(java.util.List, groovy.lang.Closure), wait(), wait(long)
groovy.lang.MissingMethodException: No signature of method: Script1.test() is applicable for argument types: () values: []
Possible solutions: getAt(java.lang.String), use([Ljava.lang.Object;), use(java.lang.Class, groovy.lang.Closure), use(java.util.List, groovy.lang.Closure), wait(), wait(long)
at Script1.run(Script1.groovy:1)
at Script1$run.call(Unknown Source)
at BindingTest.run(BindingTest.groovy:23)
Когда я добавил код трассировки следующим образом:
class MyBinding extends Binding {
def getVariable(String name) {
if (! hasVariable(name)) {
BindingTest.defVar(this)
}
println("getVariable: ${name}: ${super.getVariable(name).getClass().getName()}")
return super.getVariable(name)
}
void setVariable (String name, def val) {
println("setVariable: ${name}: ${val.getClass().getName()}")
super.setVariable(name, val)
}
def getProperty(String name) {
println("getProperty: ${name}: ${super.getProperty(name)}")
return super.getProperty(name)
}
void setProperty (String name, def val) {
println("setProperty: ${name}: ${val.getClass().getName()}")
super.setProperty(name, val)
}
}
В рабочем случае я получаю следующий вывод:
setVariable: test: Test
--- hello ---
В нерабочем случае я получаю этот вывод:
setVariable: test: Test
getVariable: test: Test
Caught: groovy.lang.MissingMethodException: No signature of method: Script1.test() is applicable for argument types: () values: []
...
Два вопроса:
- Почему в рабочем сценарии нет
getVariable
?
- В нерабочем сценарии, почему объект
Test
, возвращаемый getVariable
, получает отклонение?
Обратите внимание, что эта проблема относится только к вызываемым значениям. Если я установлю простое значение, такое как строка, в test
, то оба подхода будут работать нормально. Например, с такого рода изменениями:
...
static def defVar(def glob) {
glob.setVariable('test', '--- hello ---')
}
...
shell.parse('println(test)').run()
Я получаю следующий идентичный вывод с обоими подходами:
setVariable: test: java.lang.String
getVariable: test: java.lang.String
setVariable: test: java.lang.String
--- hello ---
Хотя я не уверен, почему setVariable
вызывают дважды. Я не смог найти никаких документов, объясняющих эти загадочные поведения. Может ли кто-нибудь здесь пролить свет на них?
Обратите внимание, что все фрагменты кода были упрощены для упрощения демонстрации проблемы, а не по их прямому назначению