我有java遗留代码,它加载一个groovy脚本并在加载的类中添加两个属性。它适用于groovy 1.7.0,但是当我尝试将groovy升级到版本1.8.0或更高版本时,它会导致稳定的错误"类生成期间的一般错误:-1 java.lang.ArrayIndexOutOfBoundsException:-1" 。 我尝试过使用groovy-all jar但结果与Spring 2.5.6或3.2.11相同。以下是maven依赖:
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>1.8.9</version>
</dependency>
重现错误的简短测试。有趣的是,添加简单属性(attrSingle)时不会发生错误,但仅在添加列表(attrList)时才会发生错误。
EDITED(添加了属性)
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)
但是使用groovy 1.7.0,这个测试打印出来:
Single=true
List=[a, b, c]
请帮忙。
答案 0 :(得分: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)));
修改
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;
}
}
}
答案 1 :(得分: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))));
此外,我们可以用ListExpression替换原始代码中的ArgumentListExpression:
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);
据我了解,自版本1.8.0起,ArgumentListExpression不接受相同类型的参数(ArgumentListExpression),它必须是ListExpression或ArrayExpression类型,至少对于setProperty方法起作用。