DATACMNS-1026 - ExtensionAwareEvaluationContextProvider now returns all overloaded methods as functions.

All overloaded methods are now available in SPeL expressions. Among methods with identical argument list from different sources in the same extension (extension, root object, aliases) the last one in the order in parens wins. If there is more than one method for an application the following rules are applied: if there is one method with exact matching types in the argument list it is used, otherwise an exception is thrown.

Original pull request: #217.
This commit is contained in:
Jens Schauder
2017-05-04 11:23:04 +02:00
committed by Oliver Gierke
parent 5dba2f4c59
commit 42621086fe
8 changed files with 440 additions and 30 deletions

View File

@@ -59,7 +59,8 @@ public class ConvertingPropertyAccessorUnitTests {
Entity entity = new Entity();
entity.id = 1L;
assertThat(getIdProperty()).hasValueSatisfying(it -> assertThat(getAccessor(entity, CONVERSION_SERVICE).getProperty(it, String.class)).hasValue("1"));
assertThat(getIdProperty()).hasValueSatisfying(
it -> assertThat(getAccessor(entity, CONVERSION_SERVICE).getProperty(it, String.class)).hasValue("1"));
}
@Test // DATACMNS-596

View File

@@ -19,6 +19,7 @@ import static org.assertj.core.api.Assertions.*;
import lombok.RequiredArgsConstructor;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
@@ -28,6 +29,7 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import org.assertj.core.api.Assertions;
import org.junit.Before;
import org.junit.Test;
import org.springframework.data.domain.PageRequest;
@@ -44,7 +46,8 @@ import org.springframework.expression.spel.standard.SpelExpressionParser;
* Unit tests {@link ExtensionAwareEvaluationContextProvider}.
*
* @author Oliver Gierke
* @author Thomas Darimont.
* @author Thomas Darimont
* @author Jens Schauder
*/
public class ExtensionAwareEvaluationContextProviderUnitTests {
@@ -219,6 +222,68 @@ public class ExtensionAwareEvaluationContextProviderUnitTests {
assertThat(counter.get()).isEqualTo(2);
}
@Test // DATACMNS-1026
public void overloadedMethodsGetResolved() throws Exception {
provider = createContextProviderWithOverloads();
// from the root object
assertThat(evaluateExpression("method()")).isEqualTo("zero");
assertThat(evaluateExpression("method(23)")).isEqualTo("single-int");
assertThat(evaluateExpression("method('hello')")).isEqualTo("single-string");
assertThat(evaluateExpression("method('one', 'two')")).isEqualTo("two");
// from the extension
assertThat(evaluateExpression("method(1, 2)")).isEqualTo("two-ints");
assertThat(evaluateExpression("method(1, 'two')")).isEqualTo("int-and-string");
}
@Test // DATACMNS-1026
public void methodFromRootObjectOverwritesMethodFromExtension() throws Exception {
provider = createContextProviderWithOverloads();
assertThat(evaluateExpression("ambiguous()")).isEqualTo("from-root");
}
@Test // DATACMNS-1026
public void aliasedMethodOverwritesMethodFromRootObject() throws Exception {
provider = createContextProviderWithOverloads();
assertThat(evaluateExpression("aliasedMethod()")).isEqualTo("methodResult");
}
@Test // DATACMNS-1026
public void exactMatchIsPreferred() throws Exception {
provider = createContextProviderWithOverloads();
assertThat(evaluateExpression("ambiguousOverloaded('aString')")).isEqualTo("string");
}
@Test // DATACMNS-1026
public void throwsExceptionWhenStillAmbiguous() throws Exception {
provider = createContextProviderWithOverloads();
assertThatExceptionOfType(IllegalStateException.class) //
.isThrownBy(() -> evaluateExpression("ambiguousOverloaded(23)")) //
.withMessageContaining("ambiguousOverloaded") //
.withMessageContaining("(java.lang.Integer)");
}
private ExtensionAwareEvaluationContextProvider createContextProviderWithOverloads() {
return new ExtensionAwareEvaluationContextProvider(Collections.singletonList( //
new DummyExtension("_first", "first") {
@Override
public Object getRootObject() {
return new RootWithOverloads();
}
}));
}
@RequiredArgsConstructor
public static class DummyExtension extends EvaluationContextExtensionSupport {
@@ -269,6 +334,22 @@ public class ExtensionAwareEvaluationContextProviderUnitTests {
public static String extensionMethod() {
return "methodResult";
}
public static String method(int i1, int i2) {
return "two-ints";
}
public static String method(int i, String s) {
return "int-and-string";
}
public static String ambiguous() {
return "from-extension-type";
}
public static String ambiguousToo() {
return "from-extension-type";
}
}
private Object evaluateExpression(String expression) {
@@ -312,4 +393,43 @@ public class ExtensionAwareEvaluationContextProviderUnitTests {
return "rootObjectInstanceMethod2";
}
}
public static class RootWithOverloads {
public String method() {
return "zero";
}
public String method(String s) {
return "single-string";
}
public String method(int i) {
return "single-int";
}
public String method(String s1, String s2) {
return "two";
}
public String ambiguous() {
return "from-root";
}
public String aliasedMethod() {
return "from-root";
}
public String ambiguousOverloaded(String s) {
return "string";
}
public String ambiguousOverloaded(Object o) {
return "object";
}
public String ambiguousOverloaded(Serializable o) {
return "serializable";
}
}
}