Polishing

This commit is contained in:
Sam Brannen 2024-08-05 15:01:41 +03:00
parent c57c2272a1
commit 8afff3359b
2 changed files with 42 additions and 44 deletions

View File

@ -32,6 +32,7 @@ import org.springframework.expression.MethodResolver;
import org.springframework.expression.spel.standard.SpelExpression; import org.springframework.expression.spel.standard.SpelExpression;
import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.expression.spel.testresources.Inventor;
import org.springframework.expression.spel.testresources.PlaceOfBirth; import org.springframework.expression.spel.testresources.PlaceOfBirth;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -48,12 +49,12 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
class MethodInvocationTests extends AbstractExpressionTests { class MethodInvocationTests extends AbstractExpressionTests {
@Test @Test
void testSimpleAccess01() { void simpleAccess() {
evaluate("getPlaceOfBirth().getCity()", "Smiljan", String.class); evaluate("getPlaceOfBirth().getCity()", "Smiljan", String.class);
} }
@Test @Test
void testStringClass() { void stringClass() {
evaluate("new java.lang.String('hello').charAt(2)", 'l', Character.class); evaluate("new java.lang.String('hello').charAt(2)", 'l', Character.class);
evaluate("new java.lang.String('hello').charAt(2).equals('l'.charAt(0))", true, Boolean.class); evaluate("new java.lang.String('hello').charAt(2).equals('l'.charAt(0))", true, Boolean.class);
evaluate("'HELLO'.toLowerCase()", "hello", String.class); evaluate("'HELLO'.toLowerCase()", "hello", String.class);
@ -61,13 +62,13 @@ class MethodInvocationTests extends AbstractExpressionTests {
} }
@Test @Test
void testNonExistentMethods() { void nonExistentMethods() {
// name is ok but madeup() does not exist // name is ok but madeup() does not exist
evaluateAndCheckError("name.madeup()", SpelMessage.METHOD_NOT_FOUND, 5); evaluateAndCheckError("name.madeup()", SpelMessage.METHOD_NOT_FOUND, 5);
} }
@Test @Test
void testWidening01() { void widening() {
// widening of int 3 to double 3 is OK // widening of int 3 to double 3 is OK
evaluate("new Double(3.0d).compareTo(8)", -1, Integer.class); evaluate("new Double(3.0d).compareTo(8)", -1, Integer.class);
evaluate("new Double(3.0d).compareTo(3)", 0, Integer.class); evaluate("new Double(3.0d).compareTo(3)", 0, Integer.class);
@ -75,18 +76,19 @@ class MethodInvocationTests extends AbstractExpressionTests {
} }
@Test @Test
void testArgumentConversion01() { void argumentConversion() {
// Rely on Double>String conversion for calling startsWith() // Rely on Double>String conversion for calling startsWith()
evaluate("new String('hello 2.0 to you').startsWith(7.0d)", false, Boolean.class); evaluate("new String('hello 2.0 to you').startsWith(7.0d)", false, Boolean.class);
evaluate("new String('7.0 foobar').startsWith(7.0d)", true, Boolean.class); evaluate("new String('7.0 foobar').startsWith(7.0d)", true, Boolean.class);
} }
@Test @Test // SPR-6760
void testMethodThrowingException_SPR6760() { void methodThrowingException() {
// Test method on inventor: throwException() // Test method on inventor: throwException()
// On 1 it will throw an IllegalArgumentException // On 1 it will throw an IllegalArgumentException.
// On 2 it will throw a RuntimeException // On 2 it will throw a RuntimeException.
// On 3 it will exit normally // On 4 it will throw a TestException.
// Otherwise, it will exit normally.
// In each case it increments the Inventor field 'counter' when invoked // In each case it increments the Inventor field 'counter' when invoked
SpelExpressionParser parser = new SpelExpressionParser(); SpelExpressionParser parser = new SpelExpressionParser();
@ -115,7 +117,6 @@ class MethodInvocationTests extends AbstractExpressionTests {
assertThat(o).isEqualTo(3); assertThat(o).isEqualTo(3);
assertThat(parser.parseExpression("counter").getValue(eContext)).isEqualTo(2); assertThat(parser.parseExpression("counter").getValue(eContext)).isEqualTo(2);
// Now cause it to throw an exception: // Now cause it to throw an exception:
eContext.setVariable("bar", 1); eContext.setVariable("bar", 1);
assertThatException() assertThatException()
@ -135,12 +136,13 @@ class MethodInvocationTests extends AbstractExpressionTests {
/** /**
* Check on first usage (when the cachedExecutor in MethodReference is null) that the exception is not wrapped. * Check on first usage (when the cachedExecutor in MethodReference is null) that the exception is not wrapped.
*/ */
@Test @Test // SPR-6941
void testMethodThrowingException_SPR6941() { void methodThrowingRuntimeException() {
// Test method on inventor: throwException() // Test method on inventor: throwException()
// On 1 it will throw an IllegalArgumentException // On 1 it will throw an IllegalArgumentException.
// On 2 it will throw a RuntimeException // On 2 it will throw a RuntimeException.
// On 3 it will exit normally // On 4 it will throw a TestException.
// Otherwise, it will exit normally.
// In each case it increments the Inventor field 'counter' when invoked // In each case it increments the Inventor field 'counter' when invoked
SpelExpressionParser parser = new SpelExpressionParser(); SpelExpressionParser parser = new SpelExpressionParser();
@ -152,12 +154,13 @@ class MethodInvocationTests extends AbstractExpressionTests {
.isNotInstanceOf(SpelEvaluationException.class); .isNotInstanceOf(SpelEvaluationException.class);
} }
@Test @Test // SPR-6941
void testMethodThrowingException_SPR6941_2() { void methodThrowingCustomException() {
// Test method on inventor: throwException() // Test method on inventor: throwException()
// On 1 it will throw an IllegalArgumentException // On 1 it will throw an IllegalArgumentException.
// On 2 it will throw a RuntimeException // On 2 it will throw a RuntimeException.
// On 3 it will exit normally // On 4 it will throw a TestException.
// Otherwise, it will exit normally.
// In each case it increments the Inventor field 'counter' when invoked // In each case it increments the Inventor field 'counter' when invoked
SpelExpressionParser parser = new SpelExpressionParser(); SpelExpressionParser parser = new SpelExpressionParser();
@ -166,12 +169,11 @@ class MethodInvocationTests extends AbstractExpressionTests {
context.setVariable("bar", 4); context.setVariable("bar", 4);
assertThatExceptionOfType(ExpressionInvocationTargetException.class) assertThatExceptionOfType(ExpressionInvocationTargetException.class)
.isThrownBy(() -> expr.getValue(context)) .isThrownBy(() -> expr.getValue(context))
.satisfies(ex -> assertThat(ex.getCause().getClass().getName()).isEqualTo( .withCauseExactlyInstanceOf(Inventor.TestException.class);
"org.springframework.expression.spel.testresources.Inventor$TestException"));
} }
@Test @Test // SPR-6764
void testMethodFiltering_SPR6764() { void methodFiltering() {
SpelExpressionParser parser = new SpelExpressionParser(); SpelExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext(); StandardEvaluationContext context = new StandardEvaluationContext();
context.setRootObject(new TestObject()); context.setRootObject(new TestObject());
@ -211,7 +213,7 @@ class MethodInvocationTests extends AbstractExpressionTests {
} }
@Test @Test
void testAddingMethodResolvers() { void addingMethodResolvers() {
StandardEvaluationContext ctx = new StandardEvaluationContext(); StandardEvaluationContext ctx = new StandardEvaluationContext();
// reflective method accessor is the only one by default // reflective method accessor is the only one by default
@ -235,7 +237,7 @@ class MethodInvocationTests extends AbstractExpressionTests {
} }
@Test @Test
void testVarargsInvocation01() { void varargsInvocation01() {
// Calling 'public String aVarargsMethod(String... strings)' // Calling 'public String aVarargsMethod(String... strings)'
evaluate("aVarargsMethod('a','b','c')", "[a, b, c]", String.class); evaluate("aVarargsMethod('a','b','c')", "[a, b, c]", String.class);
evaluate("aVarargsMethod('a')", "[a]", String.class); evaluate("aVarargsMethod('a')", "[a]", String.class);
@ -252,7 +254,7 @@ class MethodInvocationTests extends AbstractExpressionTests {
} }
@Test @Test
void testVarargsInvocation02() { void varargsInvocation02() {
// Calling 'public String aVarargsMethod2(int i, String... strings)' // Calling 'public String aVarargsMethod2(int i, String... strings)'
evaluate("aVarargsMethod2(5,'a','b','c')", "5-[a, b, c]", String.class); evaluate("aVarargsMethod2(5,'a','b','c')", "5-[a, b, c]", String.class);
evaluate("aVarargsMethod2(2,'a')", "2-[a]", String.class); evaluate("aVarargsMethod2(2,'a')", "2-[a]", String.class);
@ -267,7 +269,7 @@ class MethodInvocationTests extends AbstractExpressionTests {
} }
@Test @Test
void testVarargsInvocation03() { void varargsInvocation03() {
// Calling 'public int aVarargsMethod3(String str1, String... strings)' - returns all strings concatenated with "-" // Calling 'public int aVarargsMethod3(String str1, String... strings)' - returns all strings concatenated with "-"
// No conversion necessary // No conversion necessary
@ -295,7 +297,7 @@ class MethodInvocationTests extends AbstractExpressionTests {
} }
@Test // gh-33013 @Test // gh-33013
void testVarargsWithObjectArrayType() { void varargsWithObjectArrayType() {
// Calling 'public String formatObjectVarargs(String format, Object... args)' -> String.format(format, args) // Calling 'public String formatObjectVarargs(String format, Object... args)' -> String.format(format, args)
// No var-args and no conversion necessary // No var-args and no conversion necessary
@ -336,7 +338,7 @@ class MethodInvocationTests extends AbstractExpressionTests {
} }
@Test @Test
void testVarargsWithPrimitiveArrayType() { void varargsWithPrimitiveArrayType() {
// Calling 'public String formatPrimitiveVarargs(String format, int... nums)' -> effectively String.format(format, args) // Calling 'public String formatPrimitiveVarargs(String format, int... nums)' -> effectively String.format(format, args)
// No var-args and no conversion necessary // No var-args and no conversion necessary
@ -357,13 +359,13 @@ class MethodInvocationTests extends AbstractExpressionTests {
} }
@Test @Test
void testVarargsWithPrimitiveArrayToObjectArrayConversion() { void varargsWithPrimitiveArrayToObjectArrayConversion() {
evaluate("formatObjectVarargs('x -> %s %s %s', new short[]{1, 2, 3})", "x -> 1 2 3", String.class); // short[] to Object[] evaluate("formatObjectVarargs('x -> %s %s %s', new short[]{1, 2, 3})", "x -> 1 2 3", String.class); // short[] to Object[]
evaluate("formatObjectVarargs('x -> %s %s %s', new int[]{1, 2, 3})", "x -> 1 2 3", String.class); // int[] to Object[] evaluate("formatObjectVarargs('x -> %s %s %s', new int[]{1, 2, 3})", "x -> 1 2 3", String.class); // int[] to Object[]
} }
@Test @Test
void testVarargsOptionalInvocation() { void varargsOptionalInvocation() {
// Calling 'public String optionalVarargsMethod(Optional<String>... values)' // Calling 'public String optionalVarargsMethod(Optional<String>... values)'
evaluate("optionalVarargsMethod()", "[]", String.class); evaluate("optionalVarargsMethod()", "[]", String.class);
evaluate("optionalVarargsMethod(new String[0])", "[]", String.class); evaluate("optionalVarargsMethod(new String[0])", "[]", String.class);
@ -379,12 +381,12 @@ class MethodInvocationTests extends AbstractExpressionTests {
} }
@Test @Test
void testInvocationOnNullContextObject() { void invocationOnNullContextObject() {
evaluateAndCheckError("null.toString()",SpelMessage.METHOD_CALL_ON_NULL_OBJECT_NOT_ALLOWED); evaluateAndCheckError("null.toString()",SpelMessage.METHOD_CALL_ON_NULL_OBJECT_NOT_ALLOWED);
} }
@Test @Test
void testMethodOfClass() { void methodOfClass() {
Expression expression = parser.parseExpression("getName()"); Expression expression = parser.parseExpression("getName()");
Object value = expression.getValue(new StandardEvaluationContext(String.class)); Object value = expression.getValue(new StandardEvaluationContext(String.class));
assertThat(value).isEqualTo("java.lang.String"); assertThat(value).isEqualTo("java.lang.String");

View File

@ -119,20 +119,16 @@ public class Inventor {
public int throwException(int valueIn) throws Exception { public int throwException(int valueIn) throws Exception {
counter++; counter++;
if (valueIn==1) { switch (valueIn) {
throw new IllegalArgumentException("IllegalArgumentException for 1"); case 1 -> throw new IllegalArgumentException("IllegalArgumentException for 1");
} case 2 -> throw new RuntimeException("RuntimeException for 2");
if (valueIn==2) { case 4 -> throw new TestException();
throw new RuntimeException("RuntimeException for 2");
}
if (valueIn==4) {
throw new TestException();
} }
return valueIn; return valueIn;
} }
@SuppressWarnings("serial") @SuppressWarnings("serial")
static class TestException extends Exception {} public static class TestException extends Exception {}
public String throwException(PlaceOfBirth pob) { public String throwException(PlaceOfBirth pob) {
return pob.getCity(); return pob.getCity();