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.
This commit is contained in:
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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<User> findByAnnotatedQuery(@Param("param") String param);
|
||||
}
|
||||
|
||||
static interface ValidRepository {
|
||||
|
||||
Reference in New Issue
Block a user