Closed
Description
Affects: 5.1.12, 5.2.2
Since this change in 5.1.8.RELEASE (#22242) we are witnessing failures in evaluation of compiled SpEL expressions.
The following test exposes the issue:
public void compiledExpression_typeDeclaresInterface() {
final SpelParserConfiguration config = new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE, null);
SpelExpressionParser parser = new SpelExpressionParser(config);
final Expression expression = parser.parseExpression("name");
Person barney = new Person("Barney");
assertThat(expression.getValue(barney), is("Barney"));
assertThat(expression.getValue(barney), is("Barney"));
//This time the compiled expression will be used
assertThat(expression.getValue(barney), is("Barney"));
}
public static class Person implements Named {
private final String name;
public Person(final String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public interface Named {
String getName();
}
Running this results in the following exception:
org.springframework.expression.spel.SpelEvaluationException: EL1072E: An exception occurred whilst evaluating a compiled expression
at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:194)
at org.springframework.expression.spel.support.CompiledSpelExpressionTest.compiledExpression_typeDeclaresInterface(CompiledSpelExpressionTest.java:24)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: java.lang.IncompatibleClassChangeError: Found interface org.springframework.expression.spel.support.CompiledSpelExpressionTest$Named, but class was expected
at spel.Ex2.getValue(Unknown Source)
at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:184)
The issue looks to be with the compilation - org.springframework.expression.spel.support.ReflectivePropertyAccessor.generateCode contains the following:
if (this.member instanceof Method) {
mv.visitMethodInsn((isStatic ? INVOKESTATIC : INVOKEVIRTUAL), classDesc, this.member.getName(),
CodeFlow.createSignatureDescriptor((Method) this.member). false);
}
As we now are potentially referencing an interface, the following change fixes the issue:
if (this.member instanceof Method) {
boolean isInterface = this.member.getDeclaringClass().isInterface();
mv.visitMethodInsn((isStatic ? INVOKESTATIC : isInterface ? INVOKEINTERFACE : INVOKEVIRTUAL), classDesc, this.member.getName(),
CodeFlow.createSignatureDescriptor((Method) this.member), isInterface);
}
This has been tested against Oracle JDK 8u231 and spring-expression 5.1.12.RELEASE and 5.2.2.RELEASE. The issue is not encountered in spring-expression 5.1.7 and below.
Metadata
Metadata
Assignees
Labels
Type
Projects
Relationships
Development
No branches or pull requests
Activity
[-]IncompatibleClassChangeError encountered on evaluation of compiled SPEL expressions[/-][+]IncompatibleClassChangeError encountered on execution of compiled SPEL expressions[/+]sbrannen commentedon Jan 15, 2020
I've edited your comment to improve the formatting. You might want to check out this Mastering Markdown guide for future reference.
sbrannen commentedon Jan 15, 2020
Thanks for raising the issue.
@Smahlatz, would you be interested in submitting a PR with your patch and your test?
Smahlatz commentedon Jan 15, 2020
@sbrannen I would certainly be interested in submitting a PR, however my current terms of employment make this problematic.
9 remaining items