Using `evaluate` function. Why it doesn't work?

为君一笑 提交于 2019-12-23 07:49:23

问题


This code:

evaluate ("def test() { println \"Test is successful!\" }")
test()

results in exception:

FATAL: No signature of method: script1409644336796288198097.test() is applicable for argument types: () values: [] Possible solutions: use([Ljava.lang.Object;), getAt(java.lang.String), use(java.util.List, groovy.lang.Closure), use(java.lang.Class, groovy.lang.Closure), wait(), wait(long) groovy.lang.MissingMethodException: No signature of method: script1409644336796288198097.test() is applicable for argument types: () values: [] Possible solutions: use([Ljava.lang.Object;), getAt(java.lang.String), use(java.util.List, groovy.lang.Closure), use(java.lang.Class, groovy.lang.Closure), wait(), wait(long) at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:55) ...

What I'm doing wrong?


回答1:


That script evaluation results in null. You should either return something or execute the script and return the result.

An example returning a closure instead of defining a method:

test = evaluate ('return { "Test is successful!" }')
assert test() == "Test is successful!"

And an example where the script executes the method itself:

result = evaluate 'def test() { "eval test" }; return test()'
assert result == "eval test"

If you cannot change the script code, you may parse a class from the script, create a new object, and then execute the test() method:

def parent = getClass().getClassLoader()
def loader = new GroovyClassLoader(parent)
def clazz = loader.parseClass('def test() { "new class definition" }');

obj = clazz.newInstance()
assert obj.test() == "new class definition"



回答2:


You can do this using the ExpandoMetaClass to add dynamic closures to your own class. You would need to parse the string beforehand to split it into function name, arguments and code.

methodName = "test"
methodArgs = []
methodCode = """println "Hello World!" """

this.metaClass."$methodName"{ code, args ->
  evaluate(code)
}

Then you can call it by doing:

"$methodName"(code, arguments)

or

test(code, arguments)

To get the output Hello World!

You can read more about ExpandoMetaClass here http://groovy.codehaus.org/ExpandoMetaClass




回答3:


If a variable has an undeclared type, then it goes into the script binding. The binding is visible to all methods which means data is shared.

evaluate() is a helper method to allow the dynamic evaluation of groovy expressions using this scripts binding as the variable scope.

In a variable binding, you can declare a closure which accepts no argument and must be restricted to calls without arguments.

With all of that in mind, here is your script working as intended.

evaluate ("test = { -> println \"Test is successful!\" }")
test()



回答4:


In addition to all other answers, if you don't want to change the structure of your code you can simply use return this at the end of your groovy-string:

lib = evaluate ("def test() { println \"Test is successful!\" }; return this")
lib.test()


来源:https://stackoverflow.com/questions/25618554/using-evaluate-function-why-it-doesnt-work

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