From c8c8f5722bc58452894742534954c0935653771f Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Tue, 6 Jun 2023 14:14:15 +0200 Subject: [PATCH] Support letters other than A-Z in identifiers in SpEL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .../expression/spel/standard/Tokenizer.java | 14 ++------ .../expression/spel/ParsingTests.java | 32 ++++++++----------- 2 files changed, 16 insertions(+), 30 deletions(-) diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/standard/Tokenizer.java b/spring-expression/src/main/java/org/springframework/expression/spel/standard/Tokenizer.java index 461aaf9519..632cf4721b 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/standard/Tokenizer.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/standard/Tokenizer.java @@ -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 { 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 { 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 { } 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) { diff --git a/spring-expression/src/test/java/org/springframework/expression/spel/ParsingTests.java b/spring-expression/src/test/java/org/springframework/expression/spel/ParsingTests.java index 03e6b72dab..621a6e9e5f 100644 --- a/spring-expression/src/test/java/org/springframework/expression/spel/ParsingTests.java +++ b/spring-expression/src/test/java/org/springframework/expression/spel/ParsingTests.java @@ -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 { 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