Support nested double quotes in SpEL expressions

The Spring Expression Language currently supports nested single quotes
within expressions but not nested double quotes.

The SpEL tokenizer has been modified to support nested double quotes in
the same way it supports single quotes. A sequence of two double quotes
will now be replaced by one when evaluated.

Extra error handling has also been added to report when invalid escaping
is encountered, since SpEL does not support escaping with backslash.

Issue: SPR-9620
master
Andy Clement 12 years ago committed by Sam Brannen
parent 0d963a690b
commit 75944cc88f
  1. 3
      spring-expression/src/main/java/org/springframework/expression/spel/SpelMessage.java
  2. 4
      spring-expression/src/main/java/org/springframework/expression/spel/ast/StringLiteral.java
  3. 9
      spring-expression/src/main/java/org/springframework/expression/spel/standard/Tokenizer.java
  4. 19
      spring-expression/src/test/java/org/springframework/expression/spel/standard/SpelParserTests.java
  5. 1
      src/dist/changelog.txt

@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -104,6 +104,7 @@ public enum SpelMessage {
MISSING_ARRAY_DIMENSION(Kind.ERROR, 1063, "A required array dimension has not been specified"), //
INITIALIZER_LENGTH_INCORRECT(
Kind.ERROR, 1064, "array initializer size does not match array dimensions"), //
UNEXPECTED_ESCAPE_CHAR(Kind.ERROR,1065,"unexpected escape character.");
;
private Kind kind;

@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -31,7 +31,7 @@ public class StringLiteral extends Literal {
super(payload,pos);
// TODO should these have been skipped being created by the parser rules? or not?
value = value.substring(1, value.length() - 1);
this.value = new TypedValue(value.replaceAll("''", "'"));
this.value = new TypedValue(value.replaceAll("''", "'").replaceAll("\"\"", "\""));
}
@Override

@ -199,6 +199,8 @@ class Tokenizer {
// hit sentinel at end of value
pos++; // will take us to the end
break;
case '\\':
throw new InternalParseException(new SpelParseException(expressionString,pos,SpelMessage.UNEXPECTED_ESCAPE_CHAR));
default:
throw new IllegalStateException("Cannot handle ("+Integer.valueOf(ch)+") '"+ch+"'");
}
@ -241,7 +243,12 @@ class Tokenizer {
pos++;
char ch = toProcess[pos];
if (ch=='"') {
terminated = true;
// may not be the end if the char after is also a "
if (toProcess[pos+1]=='"') {
pos++; // skip over that too, and continue
} else {
terminated = true;
}
}
if (ch==0) {
throw new InternalParseException(new SpelParseException(expressionString,start,SpelMessage.NON_TERMINATING_DOUBLE_QUOTED_STRING));

@ -261,6 +261,25 @@ public class SpelParserTests {
assertEquals("ho", expr.getValue());
}
@Test
public void testStringLiterals_DoubleQuotes_spr9620() throws Exception {
SpelExpression expr = new SpelExpressionParser().parseRaw("\"double quote: \"\".\"");
assertEquals("double quote: \".", expr.getValue());
expr = new SpelExpressionParser().parseRaw("\"hello \"\" world\"");
assertEquals("hello \" world", expr.getValue());
}
@Test
public void testStringLiterals_DoubleQuotes_spr9620_2() throws Exception {
try {
new SpelExpressionParser().parseRaw("\"double quote: \\\"\\\".\"");
fail("Should have failed");
} catch (SpelParseException spe) {
assertEquals(17, spe.getPosition());
assertEquals(SpelMessage.UNEXPECTED_ESCAPE_CHAR, spe.getMessageCode());
}
}
@Test
public void positionalInformation() throws EvaluationException, ParseException {
SpelExpression expr = new SpelExpressionParser().parseRaw("true and true or false");

@ -10,6 +10,7 @@ Changes in version 3.2 M2 (2012-08-xx)
* now inferring return type of generic factory methods (SPR-9493)
* SpEL now supports method invocations on integers (SPR-9612)
* SpEL now supports symbolic boolean operators for OR and AND (SPR-9614)
* SpEL now supports nested double quotes in expressions (SPR-9620)
* introduced support for case-insensitive null literals in SpEL expressions (SPR-9613)
* now using BufferedInputStream in SimpleMetaDataReader to double performance (SPR-9528)
* introduced "repeatCount" property in Quartz SimpleTriggerFactoryBean (SPR-9521)

Loading…
Cancel
Save