From 26f0eec0106293e6078bc8521d9f05598abdda67 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Wed, 11 Apr 2012 20:48:34 +0200 Subject: [PATCH] DATAJPA-185 - Sanity check named parameter names in JpaQueryMethod. To avoid the query execution to fail due to typos in the named parameter mapping, JpaQueryMethod now checks the named parameters potentially annotated using @Param to be present in the annotated query. --- .../jpa/repository/query/JpaQueryMethod.java | 24 +++++++++++++++++ .../query/JpaQueryMethodUnitTests.java | 27 ++++++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java b/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java index a134701da..bbd97dc6f 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java +++ b/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java @@ -31,6 +31,7 @@ import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.QueryHints; import org.springframework.data.repository.core.RepositoryMetadata; +import org.springframework.data.repository.query.Parameter; import org.springframework.data.repository.query.Parameters; import org.springframework.data.repository.query.QueryMethod; import org.springframework.util.Assert; @@ -65,6 +66,29 @@ public class JpaQueryMethod extends QueryMethod { Assert.isTrue(!(isModifyingQuery() && getParameters().hasSpecialParameter()), String.format("Modifying method must not contain %s!", Parameters.TYPES)); + assertParameterNamesInAnnotatedQuery(); + } + + private final void assertParameterNamesInAnnotatedQuery() { + + String annotatedQuery = getAnnotatedQuery(); + + if (!StringUtils.hasText(annotatedQuery)) { + return; + } + + for (Parameter parameter : getParameters()) { + + if (!parameter.isNamedParameter()) { + continue; + } + + if (!annotatedQuery.contains(String.format(":%s", parameter.getName()))) { + throw new IllegalStateException(String.format( + "Using named parameters for method %s but parameter '%s' not found in annotated query '%s'!", method, + parameter.getName(), annotatedQuery)); + } + } } /** diff --git a/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryMethodUnitTests.java b/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryMethodUnitTests.java index 927e5793c..abaf543e2 100644 --- a/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryMethodUnitTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryMethodUnitTests.java @@ -40,6 +40,7 @@ import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.sample.UserRepository; import org.springframework.data.repository.core.RepositoryMetadata; import org.springframework.data.repository.core.support.DefaultRepositoryMetadata; +import org.springframework.data.repository.query.Param; import org.springframework.data.repository.query.QueryMethod; /** @@ -59,7 +60,7 @@ public class JpaQueryMethodUnitTests { RepositoryMetadata metadata; Method repositoryMethod, invalidReturnType, pageableAndSort, pageableTwice, sortableTwice, modifyingMethod, - nativeQuery, namedQuery, findWithLockMethod; + nativeQuery, namedQuery, findWithLockMethod, invalidNamedParameter; /** * @throws Exception @@ -80,6 +81,7 @@ public class JpaQueryMethodUnitTests { namedQuery = ValidRepository.class.getMethod("findByNamedQuery"); findWithLockMethod = ValidRepository.class.getMethod("findOneLocked", Integer.class); + invalidNamedParameter = InvalidRepository.class.getMethod("findByAnnotatedQuery", String.class); } @Test @@ -254,6 +256,25 @@ public class JpaQueryMethodUnitTests { assertThat(method.getNamedCountQueryName(), is("Foo.bar.count")); } + /** + * @see DATAJPA-185 + */ + @Test + public void rejectsInvalidNamedParameter() { + + try { + new JpaQueryMethod(invalidNamedParameter, metadata, extractor); + fail(); + } catch (IllegalStateException e) { + // Parameter from query + assertThat(e.getMessage(), containsString("foo")); + // Parameter name from annotation + assertThat(e.getMessage(), containsString("param")); + // Method name + assertThat(e.getMessage(), containsString("findByAnnotatedQuery")); + } + } + /** * Interface to define invalid repository methods for testing. * @@ -284,6 +305,10 @@ public class JpaQueryMethodUnitTests { // Modifying and Sort is not allowed @Modifying void updateMethod(String firstname, Sort sort); + + // Typo in named parameter + @Query("select u from User u where u.firstname = :foo") + List findByAnnotatedQuery(@Param("param") String param); } static interface ValidRepository {