Browse Source

Fix SpEL generated code for default method invocation

Closes gh-25706
pull/25723/head
Andy Clement 4 years ago
parent
commit
a404bf5a94
  1. 3
      spring-expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.java
  2. 2
      spring-expression/src/test/java/org/springframework/expression/spel/SpelCompilationCoverageTests.java
  3. 58
      spring-expression/src/test/java/org/springframework/expression/spel/standard/SpelCompilerTests.java

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

@ -347,7 +347,8 @@ public class MethodReference extends SpelNodeImpl { @@ -347,7 +347,8 @@ public class MethodReference extends SpelNodeImpl {
}
generateCodeForArguments(mv, cf, method, this.children);
mv.visitMethodInsn((isStaticMethod ? INVOKESTATIC : INVOKEVIRTUAL), classDesc, method.getName(),
mv.visitMethodInsn((isStaticMethod ? INVOKESTATIC : (method.isDefault() ? INVOKEINTERFACE : INVOKEVIRTUAL)),
classDesc, method.getName(),
CodeFlow.createSignatureDescriptor(method), method.getDeclaringClass().isInterface());
cf.pushDescriptor(this.exitTypeDescriptor);

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

@ -5159,7 +5159,7 @@ public class SpelCompilationCoverageTests extends AbstractExpressionTests { @@ -5159,7 +5159,7 @@ public class SpelCompilationCoverageTests extends AbstractExpressionTests {
assertThatExceptionOfType(Exception.class).isThrownBy(expression::getValue);
}
private void assertIsCompiled(Expression expression) {
public static void assertIsCompiled(Expression expression) {
try {
Field field = SpelExpression.class.getDeclaredField("compiledAst");
field.setAccessible(true);

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

@ -22,8 +22,10 @@ import org.junit.jupiter.api.Test; @@ -22,8 +22,10 @@ import org.junit.jupiter.api.Test;
import org.springframework.core.Ordered;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.SpelCompilationCoverageTests;
import org.springframework.expression.spel.SpelCompilerMode;
import org.springframework.expression.spel.SpelParserConfiguration;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import static org.assertj.core.api.Assertions.assertThat;
@ -31,6 +33,7 @@ import static org.assertj.core.api.Assertions.assertThat; @@ -31,6 +33,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* Tests for the {@link SpelCompiler}.
*
* @author Sam Brannen
* @author Andy Clement
* @since 5.1.14
*/
class SpelCompilerTests {
@ -55,5 +58,60 @@ class SpelCompilerTests { @@ -55,5 +58,60 @@ class SpelCompilerTests {
return 42;
}
}
@Test // gh-25706
void defaultMethodInvocation() {
SpelParserConfiguration config = new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE, null);
SpelExpressionParser parser = new SpelExpressionParser(config);
StandardEvaluationContext context = new StandardEvaluationContext();
Item item = new Item();
context.setRootObject(item);
Expression expression = parser.parseExpression("#root.isEditable2()");
assertThat(SpelCompiler.compile(expression)).isFalse();
assertThat(expression.getValue(context)).isEqualTo(false);
assertThat(SpelCompiler.compile(expression)).isTrue();
SpelCompilationCoverageTests.assertIsCompiled(expression);
assertThat(expression.getValue(context)).isEqualTo(false);
context.setVariable("user", new User());
expression = parser.parseExpression("#root.isEditable(#user)");
assertThat(SpelCompiler.compile(expression)).isFalse();
assertThat(expression.getValue(context)).isEqualTo(true);
assertThat(SpelCompiler.compile(expression)).isTrue();
SpelCompilationCoverageTests.assertIsCompiled(expression);
assertThat(expression.getValue(context)).isEqualTo(true);
}
public static class User {
boolean isAdmin() {
return true;
}
}
public static class Item implements Editable {
// some fields
private String someField = "";
// some getters and setters
@Override
public boolean hasSomeProperty() {
return someField != null;
}
}
public interface Editable {
default boolean isEditable(User user) {
return user.isAdmin() && hasSomeProperty();
}
default boolean isEditable2() {
return false;
}
boolean hasSomeProperty();
}
}

Loading…
Cancel
Save