From f047743cfa4edbfef76a1e32dadbfc650ee6781d Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Mon, 16 Mar 2020 15:22:01 +0100 Subject: [PATCH] DATACMNS-1683 - Rebuild quotation index from rewritten SpEL query. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We now use the correct quotation map that is based on the rewritten SpEL query to detect whether an expression was quoted. Previously, we used the quotation map from the original query. After augmenting the query with synthetic parameters, the quotation offset no longer matched the query that ß∑was under inspection and calls to SpelExtractor.isQuoted(…) could report an improper result. Original pull request: #434. --- .../repository/query/SpelQueryContext.java | 13 +++++++++++-- .../query/SpelQueryContextUnitTests.java | 19 +++++++++++++++++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/springframework/data/repository/query/SpelQueryContext.java b/src/main/java/org/springframework/data/repository/query/SpelQueryContext.java index 8767f2bc1..d3f39f63b 100644 --- a/src/main/java/org/springframework/data/repository/query/SpelQueryContext.java +++ b/src/main/java/org/springframework/data/repository/query/SpelQueryContext.java @@ -41,6 +41,7 @@ import org.springframework.util.Assert; * * @author Jens Schauder * @author Gerrit Meier + * @author Mark Paluch * @since 2.1 */ @RequiredArgsConstructor(staticName = "of") @@ -145,7 +146,7 @@ public class SpelQueryContext { /** * Parses a query string, identifies the contained SpEL expressions, replaces them with bind parameters and offers a - * {@link Map} from those bind parameters to the spel expression. + * {@link Map} from those bind parameters to the SpEL expression. *

* The parser detects quoted parts of the query string and does not detect SpEL expressions inside such quoted parts * of the query. @@ -208,7 +209,9 @@ public class SpelQueryContext { this.expressions = Collections.unmodifiableMap(expressions); this.query = resultQuery.toString(); - this.quotations = quotedAreas; + + // recreate quotation map based on rewritten query. + this.quotations = new QuotationMap(this.query); } /** @@ -220,6 +223,12 @@ public class SpelQueryContext { return query; } + /** + * Return whether the {@link #getQueryString() query} at {@code index} is quoted. + * + * @param index + * @return {@literal true} if quoted; {@literal false} otherwise. + */ public boolean isQuoted(int index) { return quotations.isQuoted(index); } diff --git a/src/test/java/org/springframework/data/repository/query/SpelQueryContextUnitTests.java b/src/test/java/org/springframework/data/repository/query/SpelQueryContextUnitTests.java index d5dae44d6..927ebf89a 100644 --- a/src/test/java/org/springframework/data/repository/query/SpelQueryContextUnitTests.java +++ b/src/test/java/org/springframework/data/repository/query/SpelQueryContextUnitTests.java @@ -23,14 +23,15 @@ import org.junit.Test; /** * Unit tests for {@link SpelQueryContext}. - * + * * @author Oliver Gierke * @author Jens Schauder + * @author Mark Paluch */ public class SpelQueryContextUnitTests { static final QueryMethodEvaluationContextProvider EVALUATION_CONTEXT_PROVIDER = QueryMethodEvaluationContextProvider.DEFAULT; - static final BiFunction PARAMETER_NAME_SOURCE = (index, spel) -> "EPP" + index; + static final BiFunction PARAMETER_NAME_SOURCE = (index, spel) -> "__$synthetic$__" + index; static final BiFunction REPLACEMENT_SOURCE = (prefix, name) -> prefix + name; @Test // DATACMNS-1258 @@ -63,4 +64,18 @@ public class SpelQueryContextUnitTests { assertThat(context.withEvaluationContextProvider(EVALUATION_CONTEXT_PROVIDER)).isNotNull(); } + + @Test // DATACMNS-1683 + public void reportsQuotationCorrectly() { + + SpelQueryContext context = SpelQueryContext.of(PARAMETER_NAME_SOURCE, REPLACEMENT_SOURCE); + + SpelQueryContext.SpelExtractor extractor = context.parse( + "select n from NetworkServer n where (LOWER(n.name) LIKE LOWER(NULLIF(text(concat('%',:#{#networkRequest.name},'%')), '')) OR :#{#networkRequest.name} IS NULL )"); + + assertThat(extractor.getQueryString()).isEqualTo( + "select n from NetworkServer n where (LOWER(n.name) LIKE LOWER(NULLIF(text(concat('%',:__$synthetic$__0,'%')), '')) OR :__$synthetic$__1 IS NULL )"); + assertThat(extractor.isQuoted(extractor.getQueryString().indexOf(":__$synthetic$__0"))).isFalse(); + assertThat(extractor.isQuoted(extractor.getQueryString().indexOf(":__$synthetic$__1"))).isFalse(); + } }