From e403796e8aa0a67fda5b336052dc5a2899ee36bd Mon Sep 17 00:00:00 2001 From: Jens Schauder Date: Mon, 18 Sep 2017 10:18:43 +0200 Subject: [PATCH] DATAJPA-1179 - Create multiple placeholders for duplicate SpELs. Before a duplicate SpEL created one placeholder but multiple bindings resulting in exceptions during parameter binding. --- .../data/jpa/repository/query/StringQuery.java | 12 +++++++++++- .../data/jpa/repository/UserRepositoryTests.java | 10 ++++++++++ .../repository/query/StringQueryUnitTests.java | 15 +++++++++++++++ .../jpa/repository/sample/UserRepository.java | 4 ++++ 4 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/springframework/data/jpa/repository/query/StringQuery.java b/src/main/java/org/springframework/data/jpa/repository/query/StringQuery.java index 26af01449..a12de1e5f 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/StringQuery.java +++ b/src/main/java/org/springframework/data/jpa/repository/query/StringQuery.java @@ -243,7 +243,7 @@ class StringQuery { } if (replacement != null) { - result = StringUtils.replace(result, matcher.group(2), replacement); + result = replaceFirst(result, matcher.group(2), replacement); } } @@ -251,6 +251,16 @@ class StringQuery { return result; } + private static String replaceFirst(String text, String substring, String replacement) { + + int index = text.indexOf(substring); + if (index < 0) { + return text; + } + + return text.substring(0, index) + replacement + text.substring(index + substring.length()); + } + private int tryFindGreatestParameterIndexIn(String query) { Matcher parameterIndexMatcher = PARAMETER_BINDING_BY_INDEX.matcher(query); diff --git a/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java b/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java index a9b963cae..455c8c8a7 100644 --- a/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java @@ -2065,6 +2065,16 @@ public class UserRepositoryTests { assertThat(query.getParameters()).hasSize(2); } + @Test // DATAJPA-1179 + public void duplicateSpelsWorkAsIntended() { + + flushTestUsers(); + + List users = repository.findUsersByDuplicateSpel("Oliver"); + + assertThat(users).hasSize(1); + } + private Page executeSpecWithSort(Sort sort) { flushTestUsers(); diff --git a/src/test/java/org/springframework/data/jpa/repository/query/StringQueryUnitTests.java b/src/test/java/org/springframework/data/jpa/repository/query/StringQueryUnitTests.java index bd4cb711f..7a98eaae5 100644 --- a/src/test/java/org/springframework/data/jpa/repository/query/StringQueryUnitTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/query/StringQueryUnitTests.java @@ -33,6 +33,7 @@ import org.springframework.data.repository.query.parser.Part.Type; * * @author Oliver Gierke * @author Thomas Darimont + * @author Jens Schauder */ public class StringQueryUnitTests { @@ -291,6 +292,20 @@ public class StringQueryUnitTests { assertThat(new StringQuery("select new Dto from A a").hasConstructorExpression(), is(false)); } + @Test // DATAJPA-1179 + public void bindingsMatchQueryForIdenticalSpelExpressions() { + + StringQuery query = new StringQuery("select a from A a where a.first = :#{#exp} or a.second = :#{#exp}"); + + List bindings = query.getParameterBindings(); + assertThat(bindings, not(empty())); + + for (ParameterBinding binding : bindings) { + assertThat(binding.getName(), notNullValue()); + assertThat(query.getQueryString(), containsString(binding.getName())); + } + } + private void assertPositionalBinding(Class bindingType, Integer position, ParameterBinding expectedBinding) { diff --git a/src/test/java/org/springframework/data/jpa/repository/sample/UserRepository.java b/src/test/java/org/springframework/data/jpa/repository/sample/UserRepository.java index e841189d7..6bf2e8bb5 100644 --- a/src/test/java/org/springframework/data/jpa/repository/sample/UserRepository.java +++ b/src/test/java/org/springframework/data/jpa/repository/sample/UserRepository.java @@ -489,6 +489,10 @@ public interface UserRepository // DATAJPA-858 List findByRolesNameContaining(String name); + // DATAJPA-1179 + @Query("select u from User u where u.firstname = :#{#firstname} and u.firstname = :#{#firstname}") + List findUsersByDuplicateSpel(@Param("firstname") String firstname); + List findRolesAndFirstnameBy(); // DATAJPA-1172