从 groovy shell 脚本复制的方法中的异常引起的错误堆栈跟踪

Incorrect stack trace from an exception in a method copied from a groovy shell script

我有一个 groovy 脚本,它定义了一个抛出异常的方法。 使用 AST 转换,我在编译时生成了一个新的 class。 然后我将这个方法从脚本复制到这个新的 class 并使 class 在运行时可用。 在运行时我创建新 class 的新对象并在堆栈跟踪中调用该方法时,我可以看到对 Script1 class 的引用,而不是新生成的 class.

Exception in thread "main" java.lang.RuntimeException
at MyGeneratedClass.myMethod(Script1.groovy:4)
at MyGeneratedClass$myMethod.call(Unknown Source)
at scripttest.ExTest.main(ExTest.groovy:35)

我能做些什么来改变它,所以我在堆栈跟踪中看不到这个 Script1.groovy class,而是在其中看到新的 class 和行号?

我的代码:

class ExTest {

    public static void main(String[] a) {
        String script = '''
def myMethod() {
        throw new RuntimeException()
}
'''
        def config = new CompilerConfiguration()
        config.addCompilationCustomizers(new MyCompilerConfiguration())
        ClassLoader classLoaderToUse = new GroovyClassLoader()
        GroovyShell shell = new GroovyShell(classLoaderToUse, new Binding(), config)
        Script parsedScript = shell.parse(script)
        def generatedClass = parsedScript.class.fields.find {it.name == 'myGeneratedClassField'}.type
        def generated = generatedClass.newInstance()
        generated.myMethod()
    }
}

class MyCompilerConfiguration extends CompilationCustomizer {

    MyCompilerConfiguration() {
        super(CompilePhase.CONVERSION)
    }

    @Override
    void call(SourceUnit source, GeneratorContext context, ClassNode currentClassNode) throws CompilationFailedException {
        def newClassAst = new AstBuilder().buildFromSpec {
            classNode('MyGeneratedClass', ClassNode.ACC_PUBLIC) {
                classNode java.lang.Object
                interfaces { classNode GroovyObject }
                mixins { }
            }
        }
        ClassNode myGeneratedClassNode = newClassAst[0]
        source.getAST().addClass(myGeneratedClassNode)
        currentClassNode.addField('myGeneratedClassField', Opcodes.ACC_PUBLIC, myGeneratedClassNode, new EmptyExpression())
        MethodNode myMethodNode = source.getAST().methods.find {it.name == 'myMethod'}
        myGeneratedClassNode.addMethod(myMethodNode.name, Opcodes.ACC_PUBLIC, myMethodNode.returnType, myMethodNode.parameters, myMethodNode.exceptions, myMethodNode.code)
    }
}

您的堆栈跟踪是正确的,您看到的 Script1.groovy:4 不是 class 的名称,而是生成此 class 的文件的名称,它位于你的情况,一个 Groovy 文件。

此名称来自与 ClassNode 关联的 CompilationUnit 中存在的 CodeSource 实例。您可以通过在 GroovyShell.parseGroovyClassLoader.parseClass 等方法中使用 GroovyCodeSource 来更改它,但我认为这是一个非常糟糕的主意! (安全、调试等思考与此对象相关)