Skip to content

IncompatibleClassChangeError encountered on execution of compiled SPEL expressions #24357

Closed
@Smahlatz

Description

@Smahlatz

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.

Activity

changed the title [-]IncompatibleClassChangeError encountered on evaluation of compiled SPEL expressions[/-] [+]IncompatibleClassChangeError encountered on execution of compiled SPEL expressions[/+] on Jan 14, 2020
sbrannen

sbrannen commented on Jan 15, 2020

@sbrannen
Member

I've edited your comment to improve the formatting. You might want to check out this Mastering Markdown guide for future reference.

sbrannen

sbrannen commented on Jan 15, 2020

@sbrannen
Member

Thanks for raising the issue.

@Smahlatz, would you be interested in submitting a PR with your patch and your test?

added
in: coreIssues in core modules (aop, beans, core, context, expression)
and removed on Jan 15, 2020
added this to the 5.2.4 milestone on Jan 15, 2020
self-assigned this
on Jan 15, 2020
Smahlatz

Smahlatz commented on Jan 15, 2020

@Smahlatz
Author

@sbrannen I would certainly be interested in submitting a PR, however my current terms of employment make this problematic.

9 remaining items

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

in: coreIssues in core modules (aop, beans, core, context, expression)status: backportedAn issue that has been backported to maintenance branchesstatus: feedback-providedFeedback has been providedtype: regressionA bug that is also a regression

Type

No type

Projects

No projects

Relationships

None yet

    Development

    No branches or pull requests

      Participants

      @sbrannen@Smahlatz@spring-projects-issues

      Issue actions

        IncompatibleClassChangeError encountered on execution of compiled SPEL expressions · Issue #24357 · spring-projects/spring-framework