2016-03-29 2 views
0

У меня есть строгий скрипт, который определяет метод, который генерирует исключение. Используя AST Transformations, я генерирую во время компиляции новый класс. Затем я копирую этот метод из сценария в этот новый класс и делаю класс доступным во время выполнения. Когда во время выполнения я создаю новый объект нового класса и вызываю метод в трассировке стека, я могу видеть ссылки на класс Script1 вместо нового сгенерированного класса.Неправильная трассировка стека из исключения в методе, скопированном из скрипта строчной оболочки

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 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) 
    } 
} 

ответ

1

Ваш StackTrace правильно, то Script1.groovy:4 вы видите, не имя класса, а имя файла, который сгенерировал этот класс, который, в вашем случае, Файл Groovy.

Это имя взято из экземпляра CodeSource, присутствующего в CompilationUnit, связанного с ClassNode. Вы можете изменить его, используя GroovyCodeSource в методах, таких как GroovyShell.parse или GroovyClassLoader.parseClass, но я думаю, что это действительно плохая идея! (безопасность, отладка и другие мысли связаны с этим объектом)