diff --git a/src/main/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQuery.java b/src/main/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQuery.java index 5cca2d2bf9..b907fdbf47 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQuery.java +++ b/src/main/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQuery.java @@ -35,15 +35,15 @@ * @author Thomas Darimont * @author Oliver Gierke * @author Tom Hombergs + * @author Michael J. Simons */ class ExpressionBasedStringQuery extends StringQuery { - private static final String EXPRESSION_PARAMETER = "?#{"; - private static final String QUOTED_EXPRESSION_PARAMETER = "?__HASH__{"; + private static final String EXPRESSION_PARAMETER = "$1#{"; + private static final String QUOTED_EXPRESSION_PARAMETER = "$1__HASH__{"; - private static final Pattern EXPRESSION_PARAMETER_QUOTING = Pattern.compile(Pattern.quote(EXPRESSION_PARAMETER)); - private static final Pattern EXPRESSION_PARAMETER_UNQUOTING = Pattern.compile(Pattern - .quote(QUOTED_EXPRESSION_PARAMETER)); + private static final Pattern EXPRESSION_PARAMETER_QUOTING = Pattern.compile("([:?])#\\{"); + private static final Pattern EXPRESSION_PARAMETER_UNQUOTING = Pattern.compile("([:?])__HASH__\\{"); private static final String ENTITY_NAME = "entityName"; private static final String ENTITY_NAME_VARIABLE = "#" + ENTITY_NAME; diff --git a/src/test/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQueryUnitTests.java b/src/test/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQueryUnitTests.java index d5db6d4dcc..a757fda895 100644 --- a/src/test/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQueryUnitTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQueryUnitTests.java @@ -34,6 +34,7 @@ * @author Oliver Gierke * @author Jens Schauder * @author Mark Paluch + * @author Michael J. Simons */ @ExtendWith(MockitoExtension.class) @MockitoSettings(strictness = Strictness.LENIENT) @@ -66,7 +67,7 @@ void renderAliasInExpressionQueryCorrectly() { void shouldDetectBindParameterCountCorrectly() { StringQuery query = new ExpressionBasedStringQuery( - "select n from NetworkServer n where (LOWER(n.name) LIKE LOWER(NULLIF(text(concat('%',:#{#networkRequest.name},'%')), '')) OR :#{#networkRequest.name} IS NULL )\"\n" + "select n from #{#entityName} n where (LOWER(n.name) LIKE LOWER(NULLIF(text(concat('%',:#{#networkRequest.name},'%')), '')) OR :#{#networkRequest.name} IS NULL )\"\n" + "+ \"AND (LOWER(n.server) LIKE LOWER(NULLIF(text(concat('%',:#{#networkRequest.server},'%')), '')) OR :#{#networkRequest.server} IS NULL)\"\n" + "+ \"AND (n.createdAt >= :#{#networkRequest.createdTime.startDateTime}) AND (n.createdAt <=:#{#networkRequest.createdTime.endDateTime})\"\n" + "+ \"AND (n.updatedAt >= :#{#networkRequest.updatedTime.startDateTime}) AND (n.updatedAt <=:#{#networkRequest.updatedTime.endDateTime})", @@ -75,4 +76,17 @@ void shouldDetectBindParameterCountCorrectly() { assertThat(query.getParameterBindings()).hasSize(8); } + @Test // GH-2228 + void shouldDetectBindParameterCountCorrectlyWithJDBCStyleParameters() { + + StringQuery query = new ExpressionBasedStringQuery( + "select n from #{#entityName} n where (LOWER(n.name) LIKE LOWER(NULLIF(text(concat('%',?#{#networkRequest.name},'%')), '')) OR ?#{#networkRequest.name} IS NULL )\"\n" + + "+ \"AND (LOWER(n.server) LIKE LOWER(NULLIF(text(concat('%',?#{#networkRequest.server},'%')), '')) OR ?#{#networkRequest.server} IS NULL)\"\n" + + "+ \"AND (n.createdAt >= ?#{#networkRequest.createdTime.startDateTime}) AND (n.createdAt <=?#{#networkRequest.createdTime.endDateTime})\"\n" + + "+ \"AND (n.updatedAt >= ?#{#networkRequest.updatedTime.startDateTime}) AND (n.updatedAt <=?#{#networkRequest.updatedTime.endDateTime})", + metadata, SPEL_PARSER); + + assertThat(query.getParameterBindings()).hasSize(8); + } + }