2014-11-23 3 views
0

У меня есть код устаревшего java, который загружает groovy-скрипт и добавляет два свойства в загруженный класс. Он отлично работает с groovy 1.7.0, но когда я пытаюсь обновить groovy до версии 1.8.0 или более поздней версии, он вызывает стабильную ошибку «Общая ошибка при генерации класса: -1 java.lang.ArrayIndexOutOfBoundsException: -1». Я пробовал использовать барабанную палочку, но результат был таким же, как у Spring 2.5.6 или 3.2.11. Ниже приведена зависимость от maven:ArrayIndexOutOfBoundsException при добавлении свойства в класс groovy

<dependency> 
    <groupId>org.codehaus.groovy</groupId> 
    <artifactId>groovy-all</artifactId> 
    <version>1.8.9</version> 
</dependency> 

Короткий тест, который воспроизводит ошибку. Интересно, что при добавлении простого свойства (attrSingle) ошибка не возникает, но только при добавлении списка (attrList).

редактируется (добавлено получение свойств)

import groovy.lang.*; 
import org.codehaus.groovy.ast.*; 
import org.codehaus.groovy.ast.expr.*; 
import org.codehaus.groovy.ast.stmt.ExpressionStatement; 
import org.codehaus.groovy.classgen.GeneratorContext; 
import org.codehaus.groovy.control.*; 
import org.junit.Test; 
import java.security.CodeSource; 
import java.util.*; 
import static org.junit.Assert.assertTrue; 

public class TestGroovyAutonomous { 

    @Test 
    public void testParsing() throws Exception { 
     SimpleCustomizedGroovyClassLoader customizedGroovyClassLoader = new SimpleCustomizedGroovyClassLoader(new GroovyClassLoader()); 
     Class<?> groovyClass; 
     try { 
     groovyClass = customizedGroovyClassLoader.parseClass(new GroovyCodeSource(
       "{fact -> fact.a != null}", 
       customizedGroovyClassLoader.generateScriptName(), 
       "/scriptSandbox")); 
     } catch (Exception e) { 
     System.out.println("Error loading class"); 
     throw e; 
     } 
     assertTrue(groovyClass != null); 
     GroovyObject groovyObject = (GroovyObject) groovyClass.newInstance(); 

     Boolean attrSingle = (Boolean) groovyObject.getProperty("attrSingle"); 
     System.out.println("Single=" + attrSingle); 

     List<String> attrList = new ArrayList<String>(); 
     Object[] objects = (Object[]) groovyObject.getProperty("attrList"); 
     for (Object o : objects) 
      attrList.add((String) o); 
     System.out.println("List=" + attrList);   
    } 

    class SimpleCustomizedGroovyClassLoader extends GroovyClassLoader { 
     public SimpleCustomizedGroovyClassLoader(ClassLoader cl) { 
      super(cl); 
     } 

     @Override 
     protected CompilationUnit createCompilationUnit(CompilerConfiguration config, CodeSource source) { 
      CompilationUnit cu = super.createCompilationUnit(config, source); 
      cu.addPhaseOperation(new CompilationUnit.PrimaryClassNodeOperation() { 
       public void call(SourceUnit sourceUnit, GeneratorContext context, ClassNode classNode) throws CompilationFailedException { 

        classNode.addObjectInitializerStatements(new ExpressionStatement(new MethodCallExpression(
          VariableExpression.THIS_EXPRESSION, "setProperty", 
          new ArgumentListExpression(new ConstantExpression("attrSingle"), 
                 new ConstantExpression(true))))); 

        ArgumentListExpression argumentListExpression = new ArgumentListExpression(); 
        for (String attributeName : Arrays.asList("a", "b", "c")) 
         argumentListExpression.addExpression(new ConstantExpression(attributeName)); 
        classNode.addObjectInitializerStatements(new ExpressionStatement(new MethodCallExpression(
          VariableExpression.THIS_EXPRESSION, "setProperty", 
          new ArgumentListExpression(new ConstantExpression("attrList"), argumentListExpression)))); 
       } 
      }, Phases.CONVERSION); 
      return cu; 
     } 
    } 
} 

И ошибка текст:

index problem in script1000001.groovy 
Error loading class 

org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed: 
General error during class generation: -1 

java.lang.ArrayIndexOutOfBoundsException: -1 
    at java.util.ArrayList.elementData(ArrayList.java:400) 
    at java.util.ArrayList.remove(ArrayList.java:477) 
    at org.codehaus.groovy.classgen.asm.OperandStack.remove(OperandStack.java:199) 
    at org.codehaus.groovy.classgen.asm.OperandStack.replace(OperandStack.java:270) 
    at org.codehaus.groovy.classgen.asm.CallSiteWriter.makeCallSite(CallSiteWriter.java:334) 
    at org.codehaus.groovy.classgen.asm.InvocationWriter.makeCall(InvocationWriter.java:187) 
    at org.codehaus.groovy.classgen.asm.InvocationWriter.makeCall(InvocationWriter.java:89) 
    at org.codehaus.groovy.classgen.asm.InvocationWriter.makeInvokeMethodCall(InvocationWriter.java:73) 
    at org.codehaus.groovy.classgen.asm.InvocationWriter.writeInvokeMethod(InvocationWriter.java:292) 
    at org.codehaus.groovy.classgen.AsmClassGenerator.visitMethodCallExpression(AsmClassGenerator.java:655) 
    at org.codehaus.groovy.ast.expr.MethodCallExpression.visit(MethodCallExpression.java:75) 
    at org.codehaus.groovy.classgen.asm.StatementWriter.writeExpressionStatement(StatementWriter.java:599) 
    at org.codehaus.groovy.classgen.asm.OptimizingStatementWriter.writeExpressionStatement(OptimizingStatementWriter.java:354) 
    at org.codehaus.groovy.classgen.AsmClassGenerator.visitExpressionStatement(AsmClassGenerator.java:501) 
    at org.codehaus.groovy.ast.stmt.ExpressionStatement.visit(ExpressionStatement.java:40) 
    at org.codehaus.groovy.classgen.asm.StatementWriter.writeBlockStatement(StatementWriter.java:80) 
    at org.codehaus.groovy.classgen.asm.OptimizingStatementWriter.writeBlockStatement(OptimizingStatementWriter.java:155) 
    at org.codehaus.groovy.classgen.AsmClassGenerator.visitBlockStatement(AsmClassGenerator.java:447) 
    at org.codehaus.groovy.ast.stmt.BlockStatement.visit(BlockStatement.java:69) 
    at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitClassCodeContainer(ClassCodeVisitorSupport.java:101) 
    at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitConstructorOrMethod(ClassCodeVisitorSupport.java:112) 
    at org.codehaus.groovy.classgen.AsmClassGenerator.visitStdMethod(AsmClassGenerator.java:311) 
    at org.codehaus.groovy.classgen.AsmClassGenerator.visitConstructorOrMethod(AsmClassGenerator.java:268) 
    at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitConstructor(ClassCodeVisitorSupport.java:119) 
    at org.codehaus.groovy.classgen.AsmClassGenerator.visitConstructor(AsmClassGenerator.java:383) 
    at org.codehaus.groovy.ast.ClassNode.visitContents(ClassNode.java:1054) 
    at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitClass(ClassCodeVisitorSupport.java:50) 
    at org.codehaus.groovy.classgen.AsmClassGenerator.visitClass(AsmClassGenerator.java:172) 
    at org.codehaus.groovy.control.CompilationUnit$14.call(CompilationUnit.java:770) 
    at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:970) 
    at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:548) 
    at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:526) 
    at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:503) 
    at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:302) 
    at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:281) 
    at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:267) 
    at x.y.TestGroovyAutonomous.testParsing(TestGroovyAutonomous.java:20) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:606) 
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45) 
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) 
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42) 
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) 
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263) 
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68) 
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47) 
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231) 
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60) 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229) 
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50) 
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222) 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:300) 
    at org.junit.runner.JUnitCore.run(JUnitCore.java:157) 
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:74) 
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:211) 
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:67) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:606) 
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134) 

Но с заводной 1.7.0 этот тест печатает:

 Single=true 
    List=[a, b, c] 

Пожалуйста, помогите.

+0

Вы пробовали обновление до версии более поздней, чем февраль 2013 года? –

+0

Запуск этого примера с результатом '2.3.6' в' BUG! исключение в фазе «генерация класса» в исходной единице «script1000002.groovy» Ошибка при появлении аргумента из операнда стека в классе script1000002 метод void (). – Opal

+0

Да, получая ту же ошибку с groovy-all 2.3.7, как говорит Опал , – GodVic

ответ

0

Я не могу сказать, что вы пытаетесь сделать, но вместо этого ...

ArgumentListExpression argumentListExpression = new ArgumentListExpression(); 
for (String attributeName : Arrays.asList("a", "b", "c")) 
    argumentListExpression.addExpression(new ConstantExpression(attributeName)); 
classNode.addObjectInitializerStatements(new ExpressionStatement(new MethodCallExpression(
         VariableExpression.THIS_EXPRESSION, "setProperty", 
         new ArgumentListExpression(new ConstantExpression("attrList"), argumentListExpression)))); 

ли этот выход на поведение вы после? ...

ArgumentListExpression argumentListExpression = new ArgumentListExpression(); 
argumentListExpression.addExpression(new ConstantExpression("attrList")) 
for (String attributeName : Arrays.asList("a", "b", "c")); 
    argumentListExpression.addExpression(new ConstantExpression(attributeName)); 
classNode.addObjectInitializerStatements(new ExpressionStatement(new MethodCallExpression(
         VariableExpression.THIS_EXPRESSION, "setProperty", argumentListExpression))); 

EDIT

package grails.boot; 

import static org.junit.Assert.assertTrue; 
import groovy.lang.GroovyClassLoader; 
import groovy.lang.GroovyCodeSource; 
import groovy.lang.GroovyObject; 

import java.security.CodeSource; 
import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.List; 

import org.codehaus.groovy.ast.ClassHelper; 
import org.codehaus.groovy.ast.ClassNode; 
import org.codehaus.groovy.ast.expr.ArgumentListExpression; 
import org.codehaus.groovy.ast.expr.ArrayExpression; 
import org.codehaus.groovy.ast.expr.ConstantExpression; 
import org.codehaus.groovy.ast.expr.Expression; 
import org.codehaus.groovy.ast.expr.MethodCallExpression; 
import org.codehaus.groovy.ast.expr.VariableExpression; 
import org.codehaus.groovy.ast.stmt.ExpressionStatement; 
import org.codehaus.groovy.classgen.GeneratorContext; 
import org.codehaus.groovy.control.CompilationFailedException; 
import org.codehaus.groovy.control.CompilationUnit; 
import org.codehaus.groovy.control.CompilerConfiguration; 
import org.codehaus.groovy.control.Phases; 
import org.codehaus.groovy.control.SourceUnit; 
import org.junit.Test; 

public class GroovyTestAutonomous { 

    @Test 
    public void testParsing() throws Exception { 
     SimpleCustomizedGroovyClassLoader customizedGroovyClassLoader = new SimpleCustomizedGroovyClassLoader(new GroovyClassLoader()); 
     Class<?> groovyClass; 
     try { 
      groovyClass = customizedGroovyClassLoader.parseClass(new GroovyCodeSource(
        "{fact -> fact.a != null}", 
        customizedGroovyClassLoader.generateScriptName(), 
        "/scriptSandbox")); 
     } catch (Exception e) { 
      System.out.println("Error loading class"); 
      throw e; 
     } 
     assertTrue(groovyClass != null); 
     GroovyObject groovyObject = (GroovyObject) groovyClass.newInstance(); 

     Boolean attrSingle = (Boolean) groovyObject.getProperty("attrSingle"); 
     System.out.println("Single=" + attrSingle); 

     List<String> attrList = new ArrayList<String>(); 
     Object[] objects = (Object[]) groovyObject.getProperty("attrList"); 
     for (Object o : objects) 
      attrList.add((String) o); 
     System.out.println("List=" + attrList); 
    } 

    class SimpleCustomizedGroovyClassLoader extends GroovyClassLoader { 
     public SimpleCustomizedGroovyClassLoader(ClassLoader cl) { 
      super(cl); 
     } 

     @Override 
     protected CompilationUnit createCompilationUnit(CompilerConfiguration config, CodeSource source) { 
      CompilationUnit cu = super.createCompilationUnit(config, source); 
      cu.addPhaseOperation(new CompilationUnit.PrimaryClassNodeOperation() { 
         public void call(SourceUnit sourceUnit, GeneratorContext context, ClassNode classNode) throws CompilationFailedException { 

          classNode.addObjectInitializerStatements(new ExpressionStatement(new MethodCallExpression(
            VariableExpression.THIS_EXPRESSION, "setProperty", 
            new ArgumentListExpression(new ConstantExpression("attrSingle"), 
            new ConstantExpression(true))))); 

          List<Expression> args = new ArrayList<Expression>(); 
          ArgumentListExpression argumentListExpression = new  ArgumentListExpression(); 
          argumentListExpression.addExpression(new ConstantExpression("attrList")); 
          for (String attributeName : Arrays.asList("a", "b", "c")) 
           args.add(new ConstantExpression(attributeName)); 

          ArrayExpression arrayExpression = new ArrayExpression(ClassHelper.make(Object.class), args); 
          argumentListExpression.addExpression(arrayExpression); 
          classNode.addObjectInitializerStatements(new ExpressionStatement(new MethodCallExpression(
            VariableExpression.THIS_EXPRESSION, "setProperty", argumentListExpression))); 
         } 
        }, Phases.CONVERSION); 
      return cu; 
     } 
    } 
} 
+0

В другом месте я прочитал следующие свойства: GroovyObject groovyObject = (GroovyObject) groovyClass.newInstance(); Boolean attrSingle = (Boolean) groovyObject.GetProperty ("attrSingle"); Список attrList = новый ArrayList (); Объект [] objects = (Object []) groovyObject.getProperty ("attrList"); for (Object o: objects) attrList.add ((String) o); – GodVic

+0

К сожалению, с вашим кодом я получаю следующую ошибку: groovy.lang.MissingMethodException: Нет сигнатуры метода: script1000001.setProperty() применим для типов аргументов: (java.lang.String, java.lang.String, java .lang.String, java.lang.String): [attrList, a, b, c] Возможные решения: setProperty (java.lang.String, java.lang.Object), setProperty (java.lang.String, java .lang.Object), getProperty (java.lang.String), getProperty (java.lang.String), getProperties() ... – GodVic

+0

Вы пытаетесь сгенерировать код, который вызывает метод setProperty и передает 'String' как первый аргумент и 'Object []' как второй аргумент? –

0

Большое спасибо, Jeff, он работает как с версиями 1.7.0, так и выше.

Следующий код, который немного ближе к первоначальной версии тоже работает:

   List<Expression> args = new ArrayList<Expression>(); 
       for (String attributeName : Arrays.asList("a", "b", "c")) 
        args.add(new ConstantExpression(attributeName)); 
       ArrayExpression arrayExpression = new ArrayExpression(ClassHelper.make(Object.class), args); 

       classNode.addObjectInitializerStatements(new ExpressionStatement(new MethodCallExpression(
         VariableExpression.THIS_EXPRESSION, "setProperty", 
         new ArgumentListExpression(new ConstantExpression("attrList"), arrayExpression)))); 

Кроме того, мы можем просто заменить ArgumentListExpression в исходном коде с ListExpression:

   ListExpression args = new ListExpression(); 
       for (String attributeName : Arrays.asList("a", "b", "c")) 
        args.addExpression(new ConstantExpression(attributeName)); 

       classNode.addObjectInitializerStatements(new ExpressionStatement(new MethodCallExpression(
         VariableExpression.THIS_EXPRESSION, "setProperty", 
         new ArgumentListExpression(new ConstantExpression("attrList"), args)))); 

в паре с изменение кода экстракции:

List<String> attrList = (ArrayList<String>) groovyObject.getProperty("attrList"); 
    System.out.println("List=" + attrList); 

Насколько я понимаю, d, поскольку версия 1.8.0 аргумент ArgumentListExpression не принимает аргумент того же типа (ArgumentListExpression), он должен быть типа ListExpression или ArrayExpression, по крайней мере, для метода setProperty.

Смежные вопросы