Skip to content

Commit c382b6f

Browse files
committed
Allow NEW and T to be used as unquoted map keys in SpEL
This change provides support for map[NEW], map[new], map[T] and map[t]. Prior to this change the 'new' and 't' had to be quoted because they were keywords in SpEL for a constructor reference and type reference respectively. Issue: SPR-11783
1 parent 72ec579 commit c382b6f

File tree

2 files changed

+78
-4
lines changed

2 files changed

+78
-4
lines changed

spring-expression/src/main/java/org/springframework/expression/spel/standard/InternalSpelExpressionParser.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -556,7 +556,13 @@ private boolean maybeEatTypeReference() {
556556
if (!typeName.stringValue().equals("T")) {
557557
return false;
558558
}
559-
nextToken();
559+
// It looks like a type reference but is T being used as a map key?
560+
Token t = nextToken();
561+
if (peekToken(TokenKind.RSQUARE)) {
562+
// looks like 'T]' (T is map key)
563+
push(new PropertyOrFieldReference(false,t.data,toPos(t)));
564+
return true;
565+
}
560566
eatToken(TokenKind.LPAREN);
561567
SpelNodeImpl node = eatPossiblyQualifiedId();
562568
// dotted qualified id
@@ -754,6 +760,12 @@ private boolean maybeEatMethodOrProperty(boolean nullSafeNavigation) {
754760
private boolean maybeEatConstructorReference() {
755761
if (peekIdentifierToken("new")) {
756762
Token newToken = nextToken();
763+
// It looks like a constructor reference but is NEW being used as a map key?
764+
if (peekToken(TokenKind.RSQUARE)) {
765+
// looks like 'NEW]' (so NEW used as map key)
766+
push(new PropertyOrFieldReference(false,newToken.data,toPos(newToken)));
767+
return true;
768+
}
757769
SpelNodeImpl possiblyQualifiedConstructorName = eatPossiblyQualifiedId();
758770
List<SpelNodeImpl> nodes = new ArrayList<SpelNodeImpl>();
759771
nodes.add(possiblyQualifiedConstructorName);

spring-expression/src/test/java/org/springframework/expression/spel/MapTests.java

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2014 the original author or authors.
2+
* Copyright 2014-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -20,9 +20,9 @@
2020
import java.util.Collections;
2121
import java.util.HashMap;
2222
import java.util.LinkedHashMap;
23+
import java.util.Map;
2324

2425
import org.junit.Test;
25-
2626
import org.springframework.expression.spel.ast.InlineMap;
2727
import org.springframework.expression.spel.standard.SpelExpression;
2828
import org.springframework.expression.spel.standard.SpelExpressionParser;
@@ -136,4 +136,66 @@ public void testInlineMapWriting() {
136136
// list should be unmodifiable
137137
evaluate("{a:1, b:2, c:3, d:4, e:5}[a]=6", "[a:1,b: 2,c: 3,d: 4,e: 5]", unmodifiableClass);
138138
}
139+
140+
@Test
141+
public void testMapKeysThatAreAlsoSpELKeywords() {
142+
SpelExpressionParser parser = new SpelExpressionParser();
143+
SpelExpression expression = null;
144+
Object o = null;
145+
146+
// expression = (SpelExpression) parser.parseExpression("foo['NEW']");
147+
// o = expression.getValue(new MapHolder());
148+
// assertEquals("VALUE",o);
149+
150+
expression = (SpelExpression) parser.parseExpression("foo[T]");
151+
o = expression.getValue(new MapHolder());
152+
assertEquals("TV", o);
153+
154+
expression = (SpelExpression) parser.parseExpression("foo[t]");
155+
o = expression.getValue(new MapHolder());
156+
assertEquals("tv", o);
157+
158+
expression = (SpelExpression) parser.parseExpression("foo[NEW]");
159+
o = expression.getValue(new MapHolder());
160+
assertEquals("VALUE", o);
161+
162+
expression = (SpelExpression) parser.parseExpression("foo[new]");
163+
o = expression.getValue(new MapHolder());
164+
assertEquals("value", o);
165+
166+
expression = (SpelExpression) parser.parseExpression("foo['abc.def']");
167+
o = expression.getValue(new MapHolder());
168+
assertEquals("value", o);
169+
170+
expression = (SpelExpression)parser.parseExpression("foo[foo[NEW]]");
171+
o = expression.getValue(new MapHolder());
172+
assertEquals("37",o);
173+
174+
expression = (SpelExpression)parser.parseExpression("foo[foo[new]]");
175+
o = expression.getValue(new MapHolder());
176+
assertEquals("38",o);
177+
178+
expression = (SpelExpression)parser.parseExpression("foo[foo[foo[T]]]");
179+
o = expression.getValue(new MapHolder());
180+
assertEquals("value",o);
181+
}
182+
183+
@SuppressWarnings({ "rawtypes", "unchecked" })
184+
public static class MapHolder {
185+
186+
public Map foo;
187+
188+
public MapHolder() {
189+
foo = new HashMap();
190+
foo.put("NEW", "VALUE");
191+
foo.put("new", "value");
192+
foo.put("T", "TV");
193+
foo.put("t", "tv");
194+
foo.put("abc.def", "value");
195+
foo.put("VALUE","37");
196+
foo.put("value","38");
197+
foo.put("TV","new");
198+
}
199+
}
200+
139201
}

0 commit comments

Comments
 (0)