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 {