从 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.parse
或 GroovyClassLoader.parseClass
等方法中使用 GroovyCodeSource
来更改它,但我认为这是一个非常糟糕的主意! (安全、调试等思考与此对象相关)
我有一个 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.parse
或 GroovyClassLoader.parseClass
等方法中使用 GroovyCodeSource
来更改它,但我认为这是一个非常糟糕的主意! (安全、调试等思考与此对象相关)