1
1
/*
2
- * Copyright 2002-2019 the original author or authors.
2
+ * Copyright 2002-2023 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
24
24
25
25
import org .junit .jupiter .api .Test ;
26
26
27
+ import org .springframework .expression .Expression ;
27
28
import org .springframework .expression .spel .ast .InlineMap ;
28
29
import org .springframework .expression .spel .standard .SpelExpression ;
29
30
import org .springframework .expression .spel .standard .SpelExpressionParser ;
35
36
* Test usage of inline maps.
36
37
*
37
38
* @author Andy Clement
39
+ * @author Sam Brannen
38
40
* @since 4.1
39
41
*/
40
- public class MapTests extends AbstractExpressionTests {
42
+ class MapTests extends AbstractExpressionTests {
41
43
42
- // if the list is full of literals then it will be of the type unmodifiableClass
44
+ // if the list is full of literals then it will be of the type unmodifiableMapClass
43
45
// rather than HashMap (or similar)
44
- Class <?> unmodifiableClass = Collections .unmodifiableMap (new LinkedHashMap <> ()).getClass ();
46
+ private static final Class <?> unmodifiableMapClass = Collections .unmodifiableMap (Map . of ()).getClass ();
45
47
46
48
47
49
@ Test
48
- public void testInlineMapCreation01 () {
49
- evaluate ("{'a':1, 'b':2, 'c':3, 'd':4, 'e':5}" , "{a=1, b=2, c=3, d=4, e=5}" , unmodifiableClass );
50
- evaluate ("{'a':1}" , "{a=1}" , unmodifiableClass );
50
+ void inlineMapCreationForLiterals () {
51
+ evaluate ("{'a':1, 'b':2, 'c':3, 'd':4, 'e':5}" , "{a=1, b=2, c=3, d=4, e=5}" , unmodifiableMapClass );
52
+ evaluate ("{'a':1}" , "{a=1}" , unmodifiableMapClass );
53
+ evaluate ("{'abc':'def', 'uvw':'xyz'}" , "{abc=def, uvw=xyz}" , unmodifiableMapClass );
54
+ evaluate ("{:}" , "{}" , unmodifiableMapClass );
51
55
}
52
56
53
57
@ Test
54
- public void testInlineMapCreation02 () {
55
- evaluate ("{'abc':'def', 'uvw':'xyz'}" , "{abc=def, uvw=xyz}" , unmodifiableClass );
56
- }
57
-
58
- @ Test
59
- public void testInlineMapCreation03 () {
60
- evaluate ("{:}" , "{}" , unmodifiableClass );
61
- }
62
-
63
- @ Test
64
- public void testInlineMapCreation04 () {
58
+ void inlineMapCreationForNonLiterals () {
65
59
evaluate ("{'key':'abc'=='xyz'}" , "{key=false}" , LinkedHashMap .class );
66
60
evaluate ("{key:'abc'=='xyz'}" , "{key=false}" , LinkedHashMap .class );
67
61
evaluate ("{key:'abc'=='xyz',key2:true}[key]" , "false" , Boolean .class );
@@ -70,43 +64,48 @@ public void testInlineMapCreation04() {
70
64
}
71
65
72
66
@ Test
73
- public void testInlineMapAndNesting () {
74
- evaluate ("{a:{a:1,b:2,c:3},b:{d:4,e:5,f:6}}" , "{a={a=1, b=2, c=3}, b={d=4, e=5, f=6}}" , unmodifiableClass );
75
- evaluate ("{a:{x:1,y:'2',z:3},b:{u:4,v:{'a','b'},w:5,x:6}}" , "{a={x=1, y=2, z=3}, b={u=4, v=[a, b], w=5, x=6}}" , unmodifiableClass );
76
- evaluate ("{a:{1,2,3},b:{4,5,6}}" , "{a=[1, 2, 3], b=[4, 5, 6]}" , unmodifiableClass );
67
+ void inlineMapAndNesting () {
68
+ evaluate ("{a:{a:1,b:2,c:3},b:{d:4,e:5,f:6}}" , "{a={a=1, b=2, c=3}, b={d=4, e=5, f=6}}" , unmodifiableMapClass );
69
+ evaluate ("{a:{x:1,y:'2',z:3},b:{u:4,v:{'a','b'},w:5,x:6}}" , "{a={x=1, y=2, z=3}, b={u=4, v=[a, b], w=5, x=6}}" , unmodifiableMapClass );
70
+ evaluate ("{a:{1,2,3},b:{4,5,6}}" , "{a=[1, 2, 3], b=[4, 5, 6]}" , unmodifiableMapClass );
77
71
}
78
72
79
73
@ Test
80
- public void testInlineMapWithFunkyKeys () {
81
- evaluate ("{#root.name:true}" ,"{Nikola Tesla=true}" ,LinkedHashMap .class );
74
+ void inlineMapWithFunkyKeys () {
75
+ evaluate ("{#root.name:true}" , "{Nikola Tesla=true}" , LinkedHashMap .class );
82
76
}
83
77
84
78
@ Test
85
- public void testInlineMapError () {
79
+ void inlineMapSyntaxError () {
86
80
parseAndCheckError ("{key:'abc'" , SpelMessage .OOD );
87
81
}
88
82
89
83
@ Test
90
- public void testRelOperatorsIs02 () {
91
- evaluate ("{a:1, b:2, c:3, d:4, e:5 } instanceof T(java.util.Map)" , "true" , Boolean .class );
84
+ void inelineMapIsInstanceOfMap () {
85
+ evaluate ("{a:1, b:2} instanceof T(java.util.Map)" , "true" , Boolean .class );
92
86
}
93
87
94
88
@ Test
95
- public void testInlineMapAndProjectionSelection () {
96
- evaluate ("{a:1,b:2,c:3,d:4,e:5,f:6}.![value>3]" , "[false, false, false, true, true, true]" , ArrayList .class );
97
- evaluate ("{a:1,b:2,c:3,d:4,e:5,f:6}.?[value>3]" , "{d=4, e=5, f=6}" , HashMap .class );
98
- evaluate ("{a:1,b:2,c:3,d:4,e:5,f:6,g:7,h:8,i:9,j:10}.?[value%2==0]" , "{b=2, d=4, f=6, h=8, j=10}" , HashMap .class );
99
- // TODO this looks like a serious issue (but not a new one): the context object against which arguments are evaluated seems wrong:
100
- // evaluate("{a:1,b:2,c:3,d:4,e:5,f:6,g:7,h:8,i:9,j:10}.?[isEven(value) == 'y']", "[2, 4, 6, 8, 10]", ArrayList.class);
89
+ void inlineMapProjection () {
90
+ evaluate ("{a:1,b:2,c:3,d:4}.![value > 2]" , "[false, false, true, true]" , ArrayList .class );
91
+ evaluate ("{a:1,b:2,c:3,d:4}.![value % 2 == 0]" , "[false, true, false, true]" , ArrayList .class );
92
+ evaluate ("{a:1,b:2,c:3,d:4}.![#isEven(value) == 'y']" , "[false, true, false, true]" , ArrayList .class );
101
93
}
102
94
103
95
@ Test
104
- public void testSetConstruction01 () {
105
- evaluate ("new java.util.HashMap().putAll({a:'a',b:'b',c:'c'})" , null , Object .class );
96
+ void inlineMapSelection () {
97
+ evaluate ("{a:1,b:2,c:3,d:4}.?[value > 2]" , "{c=3, d=4}" , HashMap .class );
98
+ evaluate ("{a:1,b:2,c:3,d:4,e:5,f:6}.?[value % 2 == 0]" , "{b=2, d=4, f=6}" , HashMap .class );
99
+ evaluate ("{a:1,b:2,c:3,d:4,e:5,f:6}.?[#isEven(value) == 'y']" , "{b=2, d=4, f=6}" , HashMap .class );
106
100
}
107
101
108
102
@ Test
109
- public void testConstantRepresentation1 () {
103
+ void mapConstruction () {
104
+ evaluate ("new java.util.HashMap().putAll({a:'a',b:'b'})" , null , Object .class );
105
+ }
106
+
107
+ @ Test
108
+ void constantMaps () {
110
109
checkConstantMap ("{f:{'a','b','c'}}" , true );
111
110
checkConstantMap ("{'a':1,'b':2,'c':3,'d':4,'e':5}" , true );
112
111
checkConstantMap ("{aaa:'abc'}" , true );
@@ -117,43 +116,37 @@ public void testConstantRepresentation1() {
117
116
checkConstantMap ("{#root.name:true}" ,false );
118
117
checkConstantMap ("{a:1,b:2,c:{d:true,e:false}}" , true );
119
118
checkConstantMap ("{a:1,b:2,c:{d:{1,2,3},e:{4,5,6},f:{'a','b','c'}}}" , true );
120
- // for nested InlineMap
121
- checkConstantMap ("{a:{k:#d}}" , false );
119
+ checkConstantMap ("{a:{k:#d}}" , false ); // nested InlineMap
122
120
checkConstantMap ("{@bean:@bean}" , false );
123
121
}
124
122
125
123
private void checkConstantMap (String expressionText , boolean expectedToBeConstant ) {
126
124
SpelExpressionParser parser = new SpelExpressionParser ();
127
125
SpelExpression expression = (SpelExpression ) parser .parseExpression (expressionText );
128
126
SpelNode node = expression .getAST ();
129
- boolean condition = node instanceof InlineMap ;
130
- assertThat (condition ).isTrue ();
131
- InlineMap inlineMap = (InlineMap ) node ;
132
- if (expectedToBeConstant ) {
133
- assertThat (inlineMap .isConstant ()).isTrue ();
134
- }
135
- else {
136
- assertThat (inlineMap .isConstant ()).isFalse ();
137
- }
127
+ assertThat (node ).isInstanceOfSatisfying (InlineMap .class , inlineMap -> {
128
+ if (expectedToBeConstant ) {
129
+ assertThat (inlineMap .isConstant ()).isTrue ();
130
+ }
131
+ else {
132
+ assertThat (inlineMap .isConstant ()).isFalse ();
133
+ }
134
+ });
138
135
}
139
136
140
137
@ Test
141
- public void testInlineMapWriting () {
142
- // list should be unmodifiable
143
- assertThatExceptionOfType (UnsupportedOperationException .class ). isThrownBy (() ->
144
- evaluate ( "{a:1, b:2, c:3, d:4, e:5}[a]=6" , "[a:1,b: 2,c: 3,d: 4,e: 5]" , unmodifiableClass ));
138
+ void inlineMapIsUnmodifiable () {
139
+ Expression expr = parser . parseExpression ( "{a:1}[a] = 6" );
140
+ assertThatExceptionOfType (UnsupportedOperationException .class )
141
+ . isThrownBy (() -> expr . getValue ( context ));
145
142
}
146
143
147
144
@ Test
148
- public void testMapKeysThatAreAlsoSpELKeywords () {
145
+ void mapKeysThatAreAlsoSpELKeywords () {
149
146
SpelExpressionParser parser = new SpelExpressionParser ();
150
147
SpelExpression expression = null ;
151
148
Object o = null ;
152
149
153
- // expression = (SpelExpression) parser.parseExpression("foo['NEW']");
154
- // o = expression.getValue(new MapHolder());
155
- // assertEquals("VALUE",o);
156
-
157
150
expression = (SpelExpression ) parser .parseExpression ("foo[T]" );
158
151
o = expression .getValue (new MapHolder ());
159
152
assertThat (o ).isEqualTo ("TV" );
@@ -162,6 +155,10 @@ public void testMapKeysThatAreAlsoSpELKeywords() {
162
155
o = expression .getValue (new MapHolder ());
163
156
assertThat (o ).isEqualTo ("tv" );
164
157
158
+ expression = (SpelExpression ) parser .parseExpression ("foo['NEW']" );
159
+ o = expression .getValue (new MapHolder ());
160
+ assertThat (o ).isEqualTo ("VALUE" );
161
+
165
162
expression = (SpelExpression ) parser .parseExpression ("foo[NEW]" );
166
163
o = expression .getValue (new MapHolder ());
167
164
assertThat (o ).isEqualTo ("VALUE" );
@@ -174,35 +171,32 @@ public void testMapKeysThatAreAlsoSpELKeywords() {
174
171
o = expression .getValue (new MapHolder ());
175
172
assertThat (o ).isEqualTo ("value" );
176
173
177
- expression = (SpelExpression )parser .parseExpression ("foo[foo[NEW]]" );
174
+ expression = (SpelExpression ) parser .parseExpression ("foo[foo[NEW]]" );
178
175
o = expression .getValue (new MapHolder ());
179
176
assertThat (o ).isEqualTo ("37" );
180
177
181
- expression = (SpelExpression )parser .parseExpression ("foo[foo[new]]" );
178
+ expression = (SpelExpression ) parser .parseExpression ("foo[foo[new]]" );
182
179
o = expression .getValue (new MapHolder ());
183
180
assertThat (o ).isEqualTo ("38" );
184
181
185
- expression = (SpelExpression )parser .parseExpression ("foo[foo[foo[T]]]" );
182
+ expression = (SpelExpression ) parser .parseExpression ("foo[foo[foo[T]]]" );
186
183
o = expression .getValue (new MapHolder ());
187
184
assertThat (o ).isEqualTo ("value" );
188
185
}
189
186
190
187
@ SuppressWarnings ({ "rawtypes" , "unchecked" })
191
- public static class MapHolder {
192
-
193
- public Map foo ;
194
-
195
- public MapHolder () {
196
- foo = new HashMap ();
197
- foo .put ("NEW" , "VALUE" );
198
- foo .put ("new" , "value" );
199
- foo .put ("T" , "TV" );
200
- foo .put ("t" , "tv" );
201
- foo .put ("abc.def" , "value" );
202
- foo .put ("VALUE" ,"37" );
203
- foo .put ("value" ,"38" );
204
- foo .put ("TV" ,"new" );
205
- }
188
+ static class MapHolder {
189
+
190
+ public Map foo = Map .of (
191
+ "NEW" , "VALUE" ,
192
+ "new" , "value" ,
193
+ "T" , "TV" ,
194
+ "t" , "tv" ,
195
+ "abc.def" , "value" ,
196
+ "VALUE" ,"37" ,
197
+ "value" ,"38" ,
198
+ "TV" ,"new"
199
+ );
206
200
}
207
201
208
202
}
0 commit comments