2

I have a piece of code that is to run a user-provided Groovy script, as follows:

def scriptText = <something user entered>
def manager = new ScriptEngineManager()
def engine = manager.getEngineByName('Groovy')

try {
    engine.eval(scriptText)
}
catch (ScriptException e) {
    println 'Script error at line ' + e.getLineNumber() + ', column ' + e.getColumnNumber() + ': ' + e.getMessage()
}

If I deliberately put an error in the input script that is supplied, this code will print the following (containing undefined line and column numbers):

Script error at line -1, column -1: javax.script.ScriptException: groovy.lang.MissingPropertyException: No such property: blah for class: Script1

I've also tried just calling Eval.me(scriptText), as the calling code is also Groovy, but then I get a large stack trace with the cause of the script error buried inside, as follows:

Exception in thread "main" groovy.lang.MissingPropertyException: No such property: blah for class: Script1
Possible solutions: class
    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:50)
    at org.codehaus.groovy.runtime.callsite.PogoGetPropertySite.getProperty(PogoGetPropertySite.java:49)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGroovyObjectGetProperty(AbstractCallSite.java:231)
    at Script1.run(Script1.groovy:6)  <---- this is the script error
    at groovy.lang.GroovyShell.evaluate(GroovyShell.java:518)
    at groovy.lang.GroovyShell.evaluate(GroovyShell.java:556)
    at groovy.lang.GroovyShell.evaluate(GroovyShell.java:527)
    at groovy.util.Eval.me(Eval.java:68)
    at groovy.util.Eval.me(Eval.java:51)
    at groovy.util.Eval$me.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
    at com.kminnovations.metrics.engine.tester.Testing.parseFile(Testing.groovy:32)
    at com.kminnovations.metrics.engine.tester.Testing$parseFile.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:120)
    at com.kminnovations.metrics.engine.tester.MetricsEngineTester.main(MetricsEngineTester.groovy:23)

Is there a way to execute script text from within a program and get precisely the location of the error in the script, so that I can display it clearly for the user who provided it?

4

1 に答える 1

1

I think you can still get the line by navigating to the root cause and searching for source like ScriptN.groovy, because ScriptEngineManager will automatically generate this name for every executed script.

def manager = new ScriptEngineManager()
def engine = manager.getEngineByName('Groovy')

try {
    engine.eval(scriptText)
} catch (javax.script.ScriptException e) {
    def cause = rootCause(e)
    def line = cause.stackTrace.find { 
        it.fileName ==~ /^Script\d+\.groovy$/ 
    }.lineNumber
    println "Line $line: $cause.message"
}

def rootCause(Exception e) {
    Throwable t = e;
    while (t.cause != null) t = t.cause;
    t
}

You might want to have more complicated rootCause like in apache.commons.ExceptionUtils

于 2013-01-24T08:34:59.333 に答える