Skip to content

Commit c8c8f57

Browse files
committed
Support letters other than A-Z in identifiers in SpEL
Prior to this commit, only the letters 'A' - 'Z' (ignoring case) were supported in identifiers (i.e., property, field, and variable names). This known (yet undocumented) limitation prevented the use of characters such as 'ü', 'ñ', 'é' as well as letters from other character sets such as Chinese, Japanese, Cyrillic, etc. This commit lifts that restriction by delegating to Character.isLetter() to determine if a character in a SpEL expression is a letter. Closes gh-30580
1 parent cd610b3 commit c8c8f57

File tree

2 files changed

+16
-30
lines changed

2 files changed

+16
-30
lines changed

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

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
* @author Andy Clement
3131
* @author Juergen Hoeller
3232
* @author Phillip Webb
33+
* @author Sam Brannen
3334
* @since 3.0
3435
*/
3536
class Tokenizer {
@@ -44,8 +45,6 @@ class Tokenizer {
4445

4546
private static final byte IS_HEXDIGIT = 0x02;
4647

47-
private static final byte IS_ALPHA = 0x04;
48-
4948
static {
5049
for (int ch = '0'; ch <= '9'; ch++) {
5150
FLAGS[ch] |= IS_DIGIT | IS_HEXDIGIT;
@@ -56,12 +55,6 @@ class Tokenizer {
5655
for (int ch = 'a'; ch <= 'f'; ch++) {
5756
FLAGS[ch] |= IS_HEXDIGIT;
5857
}
59-
for (int ch = 'A'; ch <= 'Z'; ch++) {
60-
FLAGS[ch] |= IS_ALPHA;
61-
}
62-
for (int ch = 'a'; ch <= 'z'; ch++) {
63-
FLAGS[ch] |= IS_ALPHA;
64-
}
6558
}
6659

6760

@@ -569,10 +562,7 @@ private boolean isDigit(char ch) {
569562
}
570563

571564
private boolean isAlphabetic(char ch) {
572-
if (ch > 255) {
573-
return false;
574-
}
575-
return (FLAGS[ch] & IS_ALPHA) != 0;
565+
return Character.isLetter(ch);
576566
}
577567

578568
private boolean isHexadecimalDigit(char ch) {

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

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,20 @@ void supportedCharactersInIdentifiers() {
6767
parseCheck("person_1.Age");
6868
parseCheck("person_1.__age");
6969
parseCheck("Person_1.get__age()");
70+
71+
// German characters
72+
parseCheck("begrüssung");
73+
parseCheck("#begrüssung");
74+
parseCheck("begrüssung[1]", "begrüssung.[1]"); // extra "." is needed due to erroneous logic in CompoundExpression.toStringAST()
75+
parseCheck("service.begrüssung");
76+
parseCheck("service.getBegrüssung()");
77+
parseCheck("Spaß");
78+
79+
// Spanish characters
80+
parseCheck("buenos_sueños");
81+
82+
// Chinese characters
83+
parseCheck("have乐趣()");
7084
}
7185

7286
@Test
@@ -75,24 +89,6 @@ void unsupportedCharactersInIdentifiers() {
7589
assertThatIllegalStateException()
7690
.isThrownBy(() -> parser.parseRaw("apple~banana"))
7791
.withMessage("Unsupported character '~' (126) encountered at position 6 in expression.");
78-
79-
// German characters
80-
assertThatIllegalStateException()
81-
.isThrownBy(() -> parser.parseRaw("begrüssung"))
82-
.withMessage("Unsupported character 'ü' (252) encountered at position 5 in expression.");
83-
assertThatIllegalStateException()
84-
.isThrownBy(() -> parser.parseRaw("Spaß"))
85-
.withMessage("Unsupported character 'ß' (223) encountered at position 4 in expression.");
86-
87-
// Spanish characters
88-
assertThatIllegalStateException()
89-
.isThrownBy(() -> parser.parseRaw("buenos_sueños"))
90-
.withMessage("Unsupported character 'ñ' (241) encountered at position 11 in expression.");
91-
92-
// Chinese characters
93-
assertThatIllegalStateException()
94-
.isThrownBy(() -> parser.parseRaw("have乐趣()"))
95-
.withMessage("Unsupported character '乐' (20048) encountered at position 5 in expression.");
9692
}
9793

9894
@Test

0 commit comments

Comments
 (0)