Support compilation of array and list indexing with Integer in SpEL
Prior to this commit, the Spring Expression Language (SpEL) failed to
compile an expression that indexed into an array or list using an
Integer.
This commit adds support for compilation of such expressions by
ensuring that an Integer is unboxed into an int in the compiled
bytecode.
See gh-32694
Closes gh-32908
(cherry picked from commit 079d53c8d6)
This commit is contained in:
parent
98aa03c0c9
commit
0f04052ba1
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -226,6 +226,8 @@ public class Indexer extends SpelNodeImpl {
|
|||
cf.loadTarget(mv);
|
||||
}
|
||||
|
||||
SpelNodeImpl index = this.children[0];
|
||||
|
||||
if (this.indexedType == IndexedType.ARRAY) {
|
||||
int insn;
|
||||
if ("D".equals(this.exitTypeDescriptor)) {
|
||||
|
|
@ -262,18 +264,14 @@ public class Indexer extends SpelNodeImpl {
|
|||
//depthPlusOne(exitTypeDescriptor)+"Ljava/lang/Object;");
|
||||
insn = AALOAD;
|
||||
}
|
||||
SpelNodeImpl index = this.children[0];
|
||||
cf.enterCompilationScope();
|
||||
index.generateCode(mv, cf);
|
||||
cf.exitCompilationScope();
|
||||
|
||||
generateIndexCode(mv, cf, index, int.class);
|
||||
mv.visitInsn(insn);
|
||||
}
|
||||
|
||||
else if (this.indexedType == IndexedType.LIST) {
|
||||
mv.visitTypeInsn(CHECKCAST, "java/util/List");
|
||||
cf.enterCompilationScope();
|
||||
this.children[0].generateCode(mv, cf);
|
||||
cf.exitCompilationScope();
|
||||
generateIndexCode(mv, cf, index, int.class);
|
||||
mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "get", "(I)Ljava/lang/Object;", true);
|
||||
}
|
||||
|
||||
|
|
@ -281,14 +279,14 @@ public class Indexer extends SpelNodeImpl {
|
|||
mv.visitTypeInsn(CHECKCAST, "java/util/Map");
|
||||
// Special case when the key is an unquoted string literal that will be parsed as
|
||||
// a property/field reference
|
||||
if ((this.children[0] instanceof PropertyOrFieldReference)) {
|
||||
if (index instanceof PropertyOrFieldReference) {
|
||||
PropertyOrFieldReference reference = (PropertyOrFieldReference) this.children[0];
|
||||
String mapKeyName = reference.getName();
|
||||
mv.visitLdcInsn(mapKeyName);
|
||||
}
|
||||
else {
|
||||
cf.enterCompilationScope();
|
||||
this.children[0].generateCode(mv, cf);
|
||||
index.generateCode(mv, cf);
|
||||
cf.exitCompilationScope();
|
||||
}
|
||||
mv.visitMethodInsn(
|
||||
|
|
@ -325,6 +323,11 @@ public class Indexer extends SpelNodeImpl {
|
|||
cf.pushDescriptor(this.exitTypeDescriptor);
|
||||
}
|
||||
|
||||
private void generateIndexCode(MethodVisitor mv, CodeFlow cf, SpelNodeImpl indexNode, Class<?> indexType) {
|
||||
String indexDesc = CodeFlow.toDescriptor(indexType);
|
||||
generateCodeForArgument(mv, cf, indexNode, indexDesc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toStringAST() {
|
||||
StringJoiner sj = new StringJoiner(",", "[", "]");
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -20,6 +20,8 @@ import java.io.IOException;
|
|||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
|
@ -27,7 +29,10 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.asm.MethodVisitor;
|
||||
|
|
@ -55,6 +60,7 @@ import static org.assertj.core.api.InstanceOfAssertFactories.BOOLEAN;
|
|||
* Checks SpelCompiler behavior. This should cover compilation all compiled node types.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @author Sam Brannen
|
||||
* @since 4.1
|
||||
*/
|
||||
public class SpelCompilationCoverageTests extends AbstractExpressionTests {
|
||||
|
|
@ -129,6 +135,442 @@ public class SpelCompilationCoverageTests extends AbstractExpressionTests {
|
|||
private SpelNodeImpl ast;
|
||||
|
||||
|
||||
@Nested
|
||||
class VariableReferenceTests {
|
||||
|
||||
@Test
|
||||
void userDefinedVariable() {
|
||||
EvaluationContext ctx = new StandardEvaluationContext();
|
||||
ctx.setVariable("target", "abc");
|
||||
expression = parser.parseExpression("#target");
|
||||
assertThat(expression.getValue(ctx)).isEqualTo("abc");
|
||||
assertCanCompile(expression);
|
||||
assertThat(expression.getValue(ctx)).isEqualTo("abc");
|
||||
ctx.setVariable("target", "123");
|
||||
assertThat(expression.getValue(ctx)).isEqualTo("123");
|
||||
|
||||
// Changing the variable type from String to Integer results in a
|
||||
// ClassCastException in the compiled code.
|
||||
ctx.setVariable("target", 42);
|
||||
assertThatExceptionOfType(SpelEvaluationException.class)
|
||||
.isThrownBy(() -> expression.getValue(ctx))
|
||||
.withCauseInstanceOf(ClassCastException.class);
|
||||
|
||||
ctx.setVariable("target", "abc");
|
||||
expression = parser.parseExpression("#target.charAt(0)");
|
||||
assertThat(expression.getValue(ctx)).isEqualTo('a');
|
||||
assertCanCompile(expression);
|
||||
assertThat(expression.getValue(ctx)).isEqualTo('a');
|
||||
ctx.setVariable("target", "1");
|
||||
assertThat(expression.getValue(ctx)).isEqualTo('1');
|
||||
|
||||
// Changing the variable type from String to Integer results in a
|
||||
// ClassCastException in the compiled code.
|
||||
ctx.setVariable("target", 42);
|
||||
assertThatExceptionOfType(SpelEvaluationException.class)
|
||||
.isThrownBy(() -> expression.getValue(ctx))
|
||||
.withCauseInstanceOf(ClassCastException.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Nested
|
||||
class IndexingTests {
|
||||
|
||||
@Test
|
||||
void indexIntoPrimitiveShortArray() {
|
||||
short[] shorts = { (short) 33, (short) 44, (short) 55 };
|
||||
|
||||
expression = parser.parseExpression("[2]");
|
||||
|
||||
assertThat(expression.getValue(shorts)).isEqualTo((short) 55);
|
||||
assertCanCompile(expression);
|
||||
assertThat(expression.getValue(shorts)).isEqualTo((short) 55);
|
||||
assertThat(getAst().getExitDescriptor()).isEqualTo("S");
|
||||
}
|
||||
|
||||
@Test
|
||||
void indexIntoPrimitiveByteArray() {
|
||||
byte[] bytes = { (byte) 2, (byte) 3, (byte) 4 };
|
||||
|
||||
expression = parser.parseExpression("[2]");
|
||||
|
||||
assertThat(expression.getValue(bytes)).isEqualTo((byte) 4);
|
||||
assertCanCompile(expression);
|
||||
assertThat(expression.getValue(bytes)).isEqualTo((byte) 4);
|
||||
assertThat(getAst().getExitDescriptor()).isEqualTo("B");
|
||||
}
|
||||
|
||||
@Test
|
||||
void indexIntoPrimitiveIntArray() {
|
||||
int[] ints = { 8, 9, 10 };
|
||||
|
||||
expression = parser.parseExpression("[2]");
|
||||
|
||||
assertThat(expression.getValue(ints)).isEqualTo(10);
|
||||
assertCanCompile(expression);
|
||||
assertThat(expression.getValue(ints)).isEqualTo(10);
|
||||
assertThat(getAst().getExitDescriptor()).isEqualTo("I");
|
||||
}
|
||||
|
||||
@Test
|
||||
void indexIntoPrimitiveLongArray() {
|
||||
long[] longs = { 2L, 3L, 4L };
|
||||
|
||||
expression = parser.parseExpression("[0]");
|
||||
|
||||
assertThat(expression.getValue(longs)).isEqualTo(2L);
|
||||
assertCanCompile(expression);
|
||||
assertThat(expression.getValue(longs)).isEqualTo(2L);
|
||||
assertThat(getAst().getExitDescriptor()).isEqualTo("J");
|
||||
}
|
||||
|
||||
@Test
|
||||
void indexIntoPrimitiveFloatArray() {
|
||||
float[] floats = { 6.0f, 7.0f, 8.0f };
|
||||
|
||||
expression = parser.parseExpression("[0]");
|
||||
|
||||
assertThat(expression.getValue(floats)).isEqualTo(6.0f);
|
||||
assertCanCompile(expression);
|
||||
assertThat(expression.getValue(floats)).isEqualTo(6.0f);
|
||||
assertThat(getAst().getExitDescriptor()).isEqualTo("F");
|
||||
}
|
||||
|
||||
@Test
|
||||
void indexIntoPrimitiveDoubleArray() {
|
||||
double[] doubles = { 3.0d, 4.0d, 5.0d };
|
||||
|
||||
expression = parser.parseExpression("[1]");
|
||||
|
||||
assertThat(expression.getValue(doubles)).isEqualTo(4.0d);
|
||||
assertCanCompile(expression);
|
||||
assertThat(expression.getValue(doubles)).isEqualTo(4.0d);
|
||||
assertThat(getAst().getExitDescriptor()).isEqualTo("D");
|
||||
}
|
||||
|
||||
@Test
|
||||
void indexIntoPrimitiveCharArray() {
|
||||
char[] chars = { 'a', 'b', 'c' };
|
||||
|
||||
expression = parser.parseExpression("[1]");
|
||||
|
||||
assertThat(expression.getValue(chars)).isEqualTo('b');
|
||||
assertCanCompile(expression);
|
||||
assertThat(expression.getValue(chars)).isEqualTo('b');
|
||||
assertThat(getAst().getExitDescriptor()).isEqualTo("C");
|
||||
}
|
||||
|
||||
@Test
|
||||
void indexIntoStringArray() {
|
||||
String[] strings = { "a", "b", "c" };
|
||||
|
||||
expression = parser.parseExpression("[0]");
|
||||
|
||||
assertThat(expression.getValue(strings)).isEqualTo("a");
|
||||
assertCanCompile(expression);
|
||||
assertThat(expression.getValue(strings)).isEqualTo("a");
|
||||
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/String");
|
||||
}
|
||||
|
||||
@Test
|
||||
void indexIntoNumberArray() {
|
||||
Number[] numbers = { 2, 8, 9 };
|
||||
|
||||
expression = parser.parseExpression("[1]");
|
||||
|
||||
assertThat(expression.getValue(numbers)).isEqualTo(8);
|
||||
assertCanCompile(expression);
|
||||
assertThat(expression.getValue(numbers)).isEqualTo(8);
|
||||
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Number");
|
||||
}
|
||||
|
||||
@Test
|
||||
void indexInto2DPrimitiveIntArray() {
|
||||
int[][] array = new int[][] {
|
||||
{ 1, 2, 3 },
|
||||
{ 4, 5, 6 }
|
||||
};
|
||||
|
||||
expression = parser.parseExpression("[1]");
|
||||
|
||||
assertThat(stringify(expression.getValue(array))).isEqualTo("4 5 6");
|
||||
assertCanCompile(expression);
|
||||
assertThat(stringify(expression.getValue(array))).isEqualTo("4 5 6");
|
||||
assertThat(getAst().getExitDescriptor()).isEqualTo("[I");
|
||||
|
||||
expression = parser.parseExpression("[1][2]");
|
||||
|
||||
assertThat(stringify(expression.getValue(array))).isEqualTo("6");
|
||||
assertCanCompile(expression);
|
||||
assertThat(stringify(expression.getValue(array))).isEqualTo("6");
|
||||
assertThat(getAst().getExitDescriptor()).isEqualTo("I");
|
||||
}
|
||||
|
||||
@Test
|
||||
void indexInto2DStringArray() {
|
||||
String[][] array = new String[][] {
|
||||
{ "a", "b", "c" },
|
||||
{ "d", "e", "f" }
|
||||
};
|
||||
|
||||
expression = parser.parseExpression("[1]");
|
||||
|
||||
assertThat(stringify(expression.getValue(array))).isEqualTo("d e f");
|
||||
assertCanCompile(expression);
|
||||
assertThat(getAst().getExitDescriptor()).isEqualTo("[Ljava/lang/String");
|
||||
assertThat(stringify(expression.getValue(array))).isEqualTo("d e f");
|
||||
assertThat(getAst().getExitDescriptor()).isEqualTo("[Ljava/lang/String");
|
||||
|
||||
expression = parser.parseExpression("[1][2]");
|
||||
|
||||
assertThat(stringify(expression.getValue(array))).isEqualTo("f");
|
||||
assertCanCompile(expression);
|
||||
assertThat(stringify(expression.getValue(array))).isEqualTo("f");
|
||||
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/String");
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void indexIntoArrayOfListOfString() {
|
||||
List<String>[] array = new List[] {
|
||||
Arrays.asList("a", "b", "c"),
|
||||
Arrays.asList("d", "e", "f")
|
||||
};
|
||||
|
||||
expression = parser.parseExpression("[1]");
|
||||
|
||||
assertThat(stringify(expression.getValue(array))).isEqualTo("d e f");
|
||||
assertCanCompile(expression);
|
||||
assertThat(stringify(expression.getValue(array))).isEqualTo("d e f");
|
||||
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/util/List");
|
||||
|
||||
expression = parser.parseExpression("[1][2]");
|
||||
|
||||
assertThat(stringify(expression.getValue(array))).isEqualTo("f");
|
||||
assertCanCompile(expression);
|
||||
assertThat(stringify(expression.getValue(array))).isEqualTo("f");
|
||||
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object");
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void indexIntoArrayOfMap() {
|
||||
Map<String, String>[] array = new Map[] { Collections.singletonMap("key", "value1") };
|
||||
|
||||
expression = parser.parseExpression("[0]");
|
||||
|
||||
assertThat(stringify(expression.getValue(array))).isEqualTo("{key=value1}");
|
||||
assertCanCompile(expression);
|
||||
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/util/Map");
|
||||
assertThat(stringify(expression.getValue(array))).isEqualTo("{key=value1}");
|
||||
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/util/Map");
|
||||
|
||||
expression = parser.parseExpression("[0]['key']");
|
||||
|
||||
assertThat(stringify(expression.getValue(array))).isEqualTo("value1");
|
||||
assertCanCompile(expression);
|
||||
assertThat(stringify(expression.getValue(array))).isEqualTo("value1");
|
||||
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object");
|
||||
}
|
||||
|
||||
@Test
|
||||
void indexIntoListOfString() {
|
||||
List<String> list = Arrays.asList("aaa", "bbb", "ccc");
|
||||
|
||||
expression = parser.parseExpression("[1]");
|
||||
|
||||
assertThat(expression.getValue(list)).isEqualTo("bbb");
|
||||
assertCanCompile(expression);
|
||||
assertThat(expression.getValue(list)).isEqualTo("bbb");
|
||||
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object");
|
||||
}
|
||||
|
||||
@Test
|
||||
void indexIntoListOfInteger() {
|
||||
List<Integer> list = Arrays.asList(123, 456, 789);
|
||||
|
||||
expression = parser.parseExpression("[2]");
|
||||
|
||||
assertThat(expression.getValue(list)).isEqualTo(789);
|
||||
assertCanCompile(expression);
|
||||
assertThat(expression.getValue(list)).isEqualTo(789);
|
||||
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object");
|
||||
}
|
||||
|
||||
@Test
|
||||
void indexIntoListOfStringArray() {
|
||||
List<String[]> list = Arrays.asList(
|
||||
new String[] { "a", "b", "c" },
|
||||
new String[] { "d", "e", "f" }
|
||||
);
|
||||
|
||||
expression = parser.parseExpression("[1]");
|
||||
|
||||
assertThat(stringify(expression.getValue(list))).isEqualTo("d e f");
|
||||
assertCanCompile(expression);
|
||||
assertThat(stringify(expression.getValue(list))).isEqualTo("d e f");
|
||||
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object");
|
||||
|
||||
expression = parser.parseExpression("[1][0]");
|
||||
|
||||
assertThat(stringify(expression.getValue(list))).isEqualTo("d");
|
||||
assertCanCompile(expression);
|
||||
assertThat(stringify(expression.getValue(list))).isEqualTo("d");
|
||||
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/String");
|
||||
}
|
||||
|
||||
@Test
|
||||
void indexIntoListOfIntegerArray() {
|
||||
List<Integer[]> list = Arrays.asList(
|
||||
new Integer[] { 1, 2, 3 },
|
||||
new Integer[] { 4, 5, 6 }
|
||||
);
|
||||
|
||||
expression = parser.parseExpression("[0]");
|
||||
|
||||
assertThat(stringify(expression.getValue(list))).isEqualTo("1 2 3");
|
||||
assertCanCompile(expression);
|
||||
assertThat(stringify(expression.getValue(list))).isEqualTo("1 2 3");
|
||||
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object");
|
||||
|
||||
expression = parser.parseExpression("[0][1]");
|
||||
|
||||
assertThat(expression.getValue(list)).isEqualTo(2);
|
||||
assertCanCompile(expression);
|
||||
assertThat(expression.getValue(list)).isEqualTo(2);
|
||||
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Integer");
|
||||
}
|
||||
|
||||
@Test
|
||||
void indexIntoListOfListOfString() {
|
||||
List<List<String>> list = Arrays.asList(
|
||||
Arrays.asList("a", "b", "c"),
|
||||
Arrays.asList("d", "e", "f")
|
||||
);
|
||||
|
||||
expression = parser.parseExpression("[1]");
|
||||
|
||||
assertThat(stringify(expression.getValue(list))).isEqualTo("d e f");
|
||||
assertCanCompile(expression);
|
||||
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object");
|
||||
assertThat(stringify(expression.getValue(list))).isEqualTo("d e f");
|
||||
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object");
|
||||
|
||||
expression = parser.parseExpression("[1][2]");
|
||||
|
||||
assertThat(stringify(expression.getValue(list))).isEqualTo("f");
|
||||
assertCanCompile(expression);
|
||||
assertThat(stringify(expression.getValue(list))).isEqualTo("f");
|
||||
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object");
|
||||
}
|
||||
|
||||
@Test
|
||||
void indexIntoMap() {
|
||||
Map<String, Integer> map = Collections.singletonMap("aaa", 111);
|
||||
|
||||
expression = parser.parseExpression("['aaa']");
|
||||
|
||||
assertThat(expression.getValue(map)).isEqualTo(111);
|
||||
assertCanCompile(expression);
|
||||
assertThat(expression.getValue(map)).isEqualTo(111);
|
||||
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object");
|
||||
}
|
||||
|
||||
@Test
|
||||
void indexIntoMapOfListOfString() {
|
||||
Map<String, List<String>> map = Collections.singletonMap("foo", Arrays.asList("a", "b", "c"));
|
||||
|
||||
expression = parser.parseExpression("['foo']");
|
||||
|
||||
assertThat(stringify(expression.getValue(map))).isEqualTo("a b c");
|
||||
assertCanCompile(expression);
|
||||
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object");
|
||||
assertThat(stringify(expression.getValue(map))).isEqualTo("a b c");
|
||||
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object");
|
||||
|
||||
expression = parser.parseExpression("['foo'][2]");
|
||||
|
||||
assertThat(stringify(expression.getValue(map))).isEqualTo("c");
|
||||
assertCanCompile(expression);
|
||||
assertThat(stringify(expression.getValue(map))).isEqualTo("c");
|
||||
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object");
|
||||
}
|
||||
|
||||
@Test
|
||||
void indexIntoObject() {
|
||||
TestClass6 tc = new TestClass6();
|
||||
|
||||
// field access
|
||||
expression = parser.parseExpression("['orange']");
|
||||
|
||||
assertThat(expression.getValue(tc)).isEqualTo("value1");
|
||||
assertCanCompile(expression);
|
||||
assertThat(expression.getValue(tc)).isEqualTo("value1");
|
||||
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/String");
|
||||
|
||||
// field access
|
||||
expression = parser.parseExpression("['peach']");
|
||||
|
||||
assertThat(expression.getValue(tc)).isEqualTo(34L);
|
||||
assertCanCompile(expression);
|
||||
assertThat(expression.getValue(tc)).isEqualTo(34L);
|
||||
assertThat(getAst().getExitDescriptor()).isEqualTo("J");
|
||||
|
||||
// property access (getter)
|
||||
expression = parser.parseExpression("['banana']");
|
||||
|
||||
assertThat(expression.getValue(tc)).isEqualTo("value3");
|
||||
assertCanCompile(expression);
|
||||
assertThat(expression.getValue(tc)).isEqualTo("value3");
|
||||
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/String");
|
||||
}
|
||||
|
||||
@Test // gh-32694, gh-32908
|
||||
void indexIntoArrayUsingIntegerWrapper() {
|
||||
context.setVariable("array", new int[] {1, 2, 3, 4});
|
||||
context.setVariable("index", 2);
|
||||
|
||||
expression = parser.parseExpression("#array[#index]");
|
||||
|
||||
assertThat(expression.getValue(context)).isEqualTo(3);
|
||||
assertCanCompile(expression);
|
||||
assertThat(expression.getValue(context)).isEqualTo(3);
|
||||
assertThat(getAst().getExitDescriptor()).isEqualTo("I");
|
||||
}
|
||||
|
||||
@Test // gh-32694, gh-32908
|
||||
void indexIntoListUsingIntegerWrapper() {
|
||||
context.setVariable("list", Arrays.asList(1, 2, 3, 4));
|
||||
context.setVariable("index", 2);
|
||||
|
||||
expression = parser.parseExpression("#list[#index]");
|
||||
|
||||
assertThat(expression.getValue(context)).isEqualTo(3);
|
||||
assertCanCompile(expression);
|
||||
assertThat(expression.getValue(context)).isEqualTo(3);
|
||||
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object");
|
||||
}
|
||||
|
||||
private String stringify(Object object) {
|
||||
Stream<? extends Object> stream;
|
||||
if (object instanceof Collection) {
|
||||
stream = ((Collection<?>) object).stream();
|
||||
}
|
||||
else if (object instanceof Object[]) {
|
||||
stream = Arrays.stream((Object[]) object);
|
||||
}
|
||||
else if (object instanceof int[]) {
|
||||
stream = Arrays.stream((int[]) object).mapToObj(Integer::valueOf);
|
||||
}
|
||||
else {
|
||||
return String.valueOf(object);
|
||||
}
|
||||
return stream.map(Object::toString).collect(Collectors.joining(" "));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void typeReference() {
|
||||
expression = parse("T(String)");
|
||||
|
|
|
|||
Loading…
Reference in New Issue