Skip to content

Commit a404bf5

Browse files
committed
Fix SpEL generated code for default method invocation
Closes gh-25706
1 parent 4044f4c commit a404bf5

File tree

3 files changed

+61
-2
lines changed

3 files changed

+61
-2
lines changed

spring-expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,8 @@ public void generateCode(MethodVisitor mv, CodeFlow cf) {
347347
}
348348

349349
generateCodeForArguments(mv, cf, method, this.children);
350-
mv.visitMethodInsn((isStaticMethod ? INVOKESTATIC : INVOKEVIRTUAL), classDesc, method.getName(),
350+
mv.visitMethodInsn((isStaticMethod ? INVOKESTATIC : (method.isDefault() ? INVOKEINTERFACE : INVOKEVIRTUAL)),
351+
classDesc, method.getName(),
351352
CodeFlow.createSignatureDescriptor(method), method.getDeclaringClass().isInterface());
352353
cf.pushDescriptor(this.exitTypeDescriptor);
353354

spring-expression/src/test/java/org/springframework/expression/spel/SpelCompilationCoverageTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5159,7 +5159,7 @@ private void assertGetValueFail(Expression expression) {
51595159
assertThatExceptionOfType(Exception.class).isThrownBy(expression::getValue);
51605160
}
51615161

5162-
private void assertIsCompiled(Expression expression) {
5162+
public static void assertIsCompiled(Expression expression) {
51635163
try {
51645164
Field field = SpelExpression.class.getDeclaredField("compiledAst");
51655165
field.setAccessible(true);

spring-expression/src/test/java/org/springframework/expression/spel/standard/SpelCompilerTests.java

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,18 @@
2222

2323
import org.springframework.core.Ordered;
2424
import org.springframework.expression.Expression;
25+
import org.springframework.expression.spel.SpelCompilationCoverageTests;
2526
import org.springframework.expression.spel.SpelCompilerMode;
2627
import org.springframework.expression.spel.SpelParserConfiguration;
28+
import org.springframework.expression.spel.support.StandardEvaluationContext;
2729

2830
import static org.assertj.core.api.Assertions.assertThat;
2931

3032
/**
3133
* Tests for the {@link SpelCompiler}.
3234
*
3335
* @author Sam Brannen
36+
* @author Andy Clement
3437
* @since 5.1.14
3538
*/
3639
class SpelCompilerTests {
@@ -55,5 +58,60 @@ public int getOrder() {
5558
return 42;
5659
}
5760
}
61+
62+
@Test // gh-25706
63+
void defaultMethodInvocation() {
64+
SpelParserConfiguration config = new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE, null);
65+
SpelExpressionParser parser = new SpelExpressionParser(config);
66+
67+
StandardEvaluationContext context = new StandardEvaluationContext();
68+
Item item = new Item();
69+
context.setRootObject(item);
70+
71+
Expression expression = parser.parseExpression("#root.isEditable2()");
72+
assertThat(SpelCompiler.compile(expression)).isFalse();
73+
assertThat(expression.getValue(context)).isEqualTo(false);
74+
assertThat(SpelCompiler.compile(expression)).isTrue();
75+
SpelCompilationCoverageTests.assertIsCompiled(expression);
76+
assertThat(expression.getValue(context)).isEqualTo(false);
77+
78+
context.setVariable("user", new User());
79+
expression = parser.parseExpression("#root.isEditable(#user)");
80+
assertThat(SpelCompiler.compile(expression)).isFalse();
81+
assertThat(expression.getValue(context)).isEqualTo(true);
82+
assertThat(SpelCompiler.compile(expression)).isTrue();
83+
SpelCompilationCoverageTests.assertIsCompiled(expression);
84+
assertThat(expression.getValue(context)).isEqualTo(true);
85+
}
86+
87+
public static class User {
88+
boolean isAdmin() {
89+
return true;
90+
}
91+
}
92+
93+
public static class Item implements Editable {
94+
// some fields
95+
private String someField = "";
96+
97+
// some getters and setters
98+
99+
@Override
100+
public boolean hasSomeProperty() {
101+
return someField != null;
102+
}
103+
}
104+
105+
public interface Editable {
106+
default boolean isEditable(User user) {
107+
return user.isAdmin() && hasSomeProperty();
108+
}
109+
110+
default boolean isEditable2() {
111+
return false;
112+
}
113+
114+
boolean hasSomeProperty();
115+
}
58116

59117
}

0 commit comments

Comments
 (0)