Browse Source

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
pull/30609/head
Sam Brannen 1 year ago
parent
commit
c8c8f5722b
  1. 14
      spring-expression/src/main/java/org/springframework/expression/spel/standard/Tokenizer.java
  2. 32
      spring-expression/src/test/java/org/springframework/expression/spel/ParsingTests.java

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

@ -30,6 +30,7 @@ import org.springframework.expression.spel.SpelParseException; @@ -30,6 +30,7 @@ import org.springframework.expression.spel.SpelParseException;
* @author Andy Clement
* @author Juergen Hoeller
* @author Phillip Webb
* @author Sam Brannen
* @since 3.0
*/
class Tokenizer {
@ -44,8 +45,6 @@ class Tokenizer { @@ -44,8 +45,6 @@ class Tokenizer {
private static final byte IS_HEXDIGIT = 0x02;
private static final byte IS_ALPHA = 0x04;
static {
for (int ch = '0'; ch <= '9'; ch++) {
FLAGS[ch] |= IS_DIGIT | IS_HEXDIGIT;
@ -56,12 +55,6 @@ class Tokenizer { @@ -56,12 +55,6 @@ class Tokenizer {
for (int ch = 'a'; ch <= 'f'; ch++) {
FLAGS[ch] |= IS_HEXDIGIT;
}
for (int ch = 'A'; ch <= 'Z'; ch++) {
FLAGS[ch] |= IS_ALPHA;
}
for (int ch = 'a'; ch <= 'z'; ch++) {
FLAGS[ch] |= IS_ALPHA;
}
}
@ -569,10 +562,7 @@ class Tokenizer { @@ -569,10 +562,7 @@ class Tokenizer {
}
private boolean isAlphabetic(char ch) {
if (ch > 255) {
return false;
}
return (FLAGS[ch] & IS_ALPHA) != 0;
return Character.isLetter(ch);
}
private boolean isHexadecimalDigit(char ch) {

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

@ -67,6 +67,20 @@ class ParsingTests { @@ -67,6 +67,20 @@ class ParsingTests {
parseCheck("person_1.Age");
parseCheck("person_1.__age");
parseCheck("Person_1.get__age()");
// German characters
parseCheck("begrüssung");
parseCheck("#begrüssung");
parseCheck("begrüssung[1]", "begrüssung.[1]"); // extra "." is needed due to erroneous logic in CompoundExpression.toStringAST()
parseCheck("service.begrüssung");
parseCheck("service.getBegrüssung()");
parseCheck("Spaß");
// Spanish characters
parseCheck("buenos_sueños");
// Chinese characters
parseCheck("have乐趣()");
}
@Test
@ -75,24 +89,6 @@ class ParsingTests { @@ -75,24 +89,6 @@ class ParsingTests {
assertThatIllegalStateException()
.isThrownBy(() -> parser.parseRaw("apple~banana"))
.withMessage("Unsupported character '~' (126) encountered at position 6 in expression.");
// German characters
assertThatIllegalStateException()
.isThrownBy(() -> parser.parseRaw("begrüssung"))
.withMessage("Unsupported character 'ü' (252) encountered at position 5 in expression.");
assertThatIllegalStateException()
.isThrownBy(() -> parser.parseRaw("Spaß"))
.withMessage("Unsupported character 'ß' (223) encountered at position 4 in expression.");
// Spanish characters
assertThatIllegalStateException()
.isThrownBy(() -> parser.parseRaw("buenos_sueños"))
.withMessage("Unsupported character 'ñ' (241) encountered at position 11 in expression.");
// Chinese characters
assertThatIllegalStateException()
.isThrownBy(() -> parser.parseRaw("have乐趣()"))
.withMessage("Unsupported character '乐' (20048) encountered at position 5 in expression.");
}
@Test

Loading…
Cancel
Save