Skip to content

Commit 807ec47

Browse files
DATAMONGO-1603 - Fix Placeholder not replaced correctly in @query.
Fix issues when placeholders are appended with other chars eg. '?0xyz' or have been reused multiple times within the query.
1 parent 88fb3e3 commit 807ec47

File tree

3 files changed

+72
-5
lines changed

3 files changed

+72
-5
lines changed

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/ExpressionEvaluatingParameterBinder.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ private Pattern createReplacementPattern(List<ParameterBinding> bindings) {
247247

248248
regex.append("|");
249249
regex.append("(" + Pattern.quote(binding.getParameter()) + ")");
250-
regex.append("(\\W?['\"])?"); // potential quotation char (as in { foo : '?0' }).
250+
regex.append("(\\W?['\"]|\\w*')?");
251251
}
252252

253253
return Pattern.compile(regex.substring(1));
@@ -271,9 +271,16 @@ private Placeholder extractPlaceholder(int parameterIndex, Matcher matcher) {
271271
if (!StringUtils.hasText(rawPlaceholder)) {
272272

273273
rawPlaceholder = matcher.group();
274-
suffix = "" + rawPlaceholder.charAt(rawPlaceholder.length() - 1);
274+
if(rawPlaceholder.matches(".*\\d$")) {
275+
suffix = "";
276+
} else {
277+
int index = rawPlaceholder.replaceAll("[^\\?a-zA-Z0-9]*$", "").length() - 1;
278+
if(index > 1) {
279+
suffix = rawPlaceholder.substring(index);
280+
}
281+
}
275282
if (QuotedString.endsWithQuote(rawPlaceholder)) {
276-
rawPlaceholder = QuotedString.unquoteSuffix(rawPlaceholder);
283+
rawPlaceholder = rawPlaceholder.substring(0, rawPlaceholder.length() - (StringUtils.hasText(suffix) ? suffix.length() : 1));
277284
}
278285
}
279286

@@ -284,6 +291,7 @@ private Placeholder extractPlaceholder(int parameterIndex, Matcher matcher) {
284291
return Placeholder.of(parameterIndex, rawPlaceholder, quoted,
285292
quoted ? QuotedString.unquoteSuffix(suffix) : suffix);
286293
}
294+
return Placeholder.of(parameterIndex, rawPlaceholder, false, null);
287295
}
288296

289297
return Placeholder.of(parameterIndex, matcher.group(), false, null);

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/StringBasedMongoQuery.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -339,8 +339,7 @@ private static void potentiallyAddBinding(String source, List<ParameterBinding>
339339
while (valueMatcher.find()) {
340340

341341
int paramIndex = Integer.parseInt(valueMatcher.group(PARAMETER_INDEX_GROUP));
342-
boolean quoted = (source.startsWith("'") && source.endsWith("'"))
343-
|| (source.startsWith("\"") && source.endsWith("\""));
342+
boolean quoted = source.startsWith("'") || source.startsWith("\"");
344343

345344
bindings.add(new ParameterBinding(paramIndex, quoted));
346345
}

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/StringBasedMongoQueryUnitTests.java

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,54 @@ public void shouldReplaceParametersInInQuotedExpressionOfNestedQueryOperator() t
437437
assertThat(query.getQueryObject(), is((DBObject) new BasicDBObject("lastname", Pattern.compile("^(calamity)"))));
438438
}
439439

440+
@Test // DATAMONGO-1603
441+
public void shouldAllowReuseOfPlaceholderWithinQuery() throws Exception {
442+
443+
StringBasedMongoQuery mongoQuery = createQueryForMethod("findByReusingPlaceholdersMultipleTimes", String.class,
444+
String.class);
445+
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter, "calamity", "regalia");
446+
447+
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accessor);
448+
assertThat(query.getQueryObject(), is((DBObject) new BasicDBObject().append("arg0", "calamity")
449+
.append("arg1", "regalia").append("arg2", "calamity")));
450+
}
451+
452+
@Test // DATAMONGO-1603
453+
public void shouldAllowReuseOfQuotedPlaceholderWithinQuery() throws Exception {
454+
455+
StringBasedMongoQuery mongoQuery = createQueryForMethod("findByReusingPlaceholdersMultipleTimesWhenQuoted",
456+
String.class, String.class);
457+
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter, "calamity", "regalia");
458+
459+
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accessor);
460+
assertThat(query.getQueryObject(), is((DBObject) new BasicDBObject().append("arg0", "calamity")
461+
.append("arg1", "regalia").append("arg2", "calamity")));
462+
}
463+
464+
@Test // DATAMONGO-1603
465+
public void shouldAllowReuseOfQuotedPlaceholderWithinQueryAndIncludeSuffixCorrectly() throws Exception {
466+
467+
StringBasedMongoQuery mongoQuery = createQueryForMethod(
468+
"findByReusingPlaceholdersMultipleTimesWhenQuotedAndSomeStuffAppended", String.class, String.class);
469+
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter, "calamity", "regalia");
470+
471+
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accessor);
472+
assertThat(query.getQueryObject(), is((DBObject) new BasicDBObject().append("arg0", "calamity")
473+
.append("arg1", "regalia").append("arg2", "calamitys")));
474+
}
475+
476+
@Test // DATAMONGO-1603
477+
public void shouldAllowQuotedParameterWithSuffixAppended() throws Exception {
478+
479+
StringBasedMongoQuery mongoQuery = createQueryForMethod("findByWhenQuotedAndSomeStuffAppended", String.class,
480+
String.class);
481+
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter, "calamity", "regalia");
482+
483+
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accessor);
484+
assertThat(query.getQueryObject(),
485+
is((DBObject) new BasicDBObject().append("arg0", "calamity").append("arg1", "regalias")));
486+
}
487+
440488
private StringBasedMongoQuery createQueryForMethod(String name, Class<?>... parameters) throws Exception {
441489

442490
Method method = SampleRepository.class.getMethod(name, parameters);
@@ -510,5 +558,17 @@ private interface SampleRepository extends Repository<Person, Long> {
510558

511559
@Query("{ 'arg0' : ?0 }")
512560
List<Person> findByWithBsonArgument(DBObject arg0);
561+
562+
@Query("{ 'arg0' : ?0, 'arg1' : ?1, 'arg2' : ?0 }")
563+
List<Person> findByReusingPlaceholdersMultipleTimes(String arg0, String arg1);
564+
565+
@Query("{ 'arg0' : ?0, 'arg1' : ?1, 'arg2' : '?0' }")
566+
List<Person> findByReusingPlaceholdersMultipleTimesWhenQuoted(String arg0, String arg1);
567+
568+
@Query("{ 'arg0' : '?0', 'arg1' : ?1, 'arg2' : '?0s' }")
569+
List<Person> findByReusingPlaceholdersMultipleTimesWhenQuotedAndSomeStuffAppended(String arg0, String arg1);
570+
571+
@Query("{ 'arg0' : '?0', 'arg1' : '?1s' }")
572+
List<Person> findByWhenQuotedAndSomeStuffAppended(String arg0, String arg1);
513573
}
514574
}

0 commit comments

Comments
 (0)