Browse Source

Improve query method validation exceptions for declared queries.

When validating manually declared queries on repositories, the exception that captures the query to validate now actually also reports it in the exception message.

Closes: #2736.
Original pull request: #2738
pull/4129/head
Oliver Drotbohm 3 years ago committed by Mark Paluch
parent
commit
d854c63f12
No known key found for this signature in database
GPG Key ID: 55BC6374BAA9D973
  1. 28
      spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/SimpleJpaQuery.java
  2. 6
      spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/SimpleJpaQueryUnitTests.java

28
spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/SimpleJpaQuery.java

@ -40,13 +40,13 @@ final class SimpleJpaQuery extends AbstractStringBasedJpaQuery { @@ -40,13 +40,13 @@ final class SimpleJpaQuery extends AbstractStringBasedJpaQuery {
*
* @param method must not be {@literal null}
* @param em must not be {@literal null}
* @param countQueryString
* @param sourceQuery the original source query, must not be {@literal null} or empty.
* @param queryRewriter must not be {@literal null}
* @param valueExpressionDelegate must not be {@literal null}
*/
public SimpleJpaQuery(JpaQueryMethod method, EntityManager em, @Nullable String countQueryString,
public SimpleJpaQuery(JpaQueryMethod method, EntityManager em, @Nullable String sourceQuery,
QueryRewriter queryRewriter, ValueExpressionDelegate valueExpressionDelegate) {
this(method, em, method.getRequiredAnnotatedQuery(), countQueryString, queryRewriter, valueExpressionDelegate);
this(method, em, method.getRequiredAnnotatedQuery(), sourceQuery, queryRewriter, valueExpressionDelegate);
}
/**
@ -54,21 +54,20 @@ final class SimpleJpaQuery extends AbstractStringBasedJpaQuery { @@ -54,21 +54,20 @@ final class SimpleJpaQuery extends AbstractStringBasedJpaQuery {
*
* @param method must not be {@literal null}
* @param em must not be {@literal null}
* @param queryString must not be {@literal null} or empty
* @param sourceQuery the original source query, must not be {@literal null} or empty
* @param countQueryString
* @param queryRewriter
* @param valueExpressionDelegate must not be {@literal null}
*/
public SimpleJpaQuery(JpaQueryMethod method, EntityManager em, String queryString, @Nullable String countQueryString, QueryRewriter queryRewriter,
ValueExpressionDelegate valueExpressionDelegate) {
public SimpleJpaQuery(JpaQueryMethod method, EntityManager em, String sourceQuery, @Nullable String countQueryString,
QueryRewriter queryRewriter, ValueExpressionDelegate valueExpressionDelegate) {
super(method, em, queryString, countQueryString, queryRewriter, valueExpressionDelegate);
super(method, em, sourceQuery, countQueryString, queryRewriter, valueExpressionDelegate);
validateQuery(getQuery().getQueryString(), "Validation failed for query for method %s", method);
validateQuery(getQuery(), "Validation failed for query %s for method %s", method);
if (method.isPageQuery()) {
validateQuery(getCountQuery().getQueryString(),
String.format("Count query validation failed for method %s", method));
validateQuery(getCountQuery(), "Count query %s validation failed for method %s", method);
}
}
@ -78,23 +77,24 @@ final class SimpleJpaQuery extends AbstractStringBasedJpaQuery { @@ -78,23 +77,24 @@ final class SimpleJpaQuery extends AbstractStringBasedJpaQuery {
* @param query
* @param errorMessage
*/
private void validateQuery(String query, String errorMessage, Object... arguments) {
private void validateQuery(DeclaredQuery query, String errorMessage, JpaQueryMethod method) {
if (getQueryMethod().isProcedureQuery()) {
return;
}
EntityManager validatingEm = null;
var queryString = query.getQueryString();
try {
validatingEm = getEntityManager().getEntityManagerFactory().createEntityManager();
validatingEm.createQuery(query);
validatingEm.createQuery(queryString);
} catch (RuntimeException e) {
// Needed as there's ambiguities in how an invalid query string shall be expressed by the persistence provider
// https://java.net/projects/jpa-spec/lists/jsr338-experts/archive/2012-07/message/17
throw new IllegalArgumentException(String.format(errorMessage, arguments), e);
// https://download.oracle.com/javaee-archive/jpa-spec.java.net/users/2012/07/0404.html
throw new IllegalArgumentException(errorMessage.formatted(query, method), e);
} finally {

6
spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/SimpleJpaQueryUnitTests.java

@ -40,7 +40,6 @@ import org.mockito.Mockito; @@ -40,7 +40,6 @@ import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
@ -194,14 +193,15 @@ class SimpleJpaQueryUnitTests { @@ -194,14 +193,15 @@ class SimpleJpaQueryUnitTests {
}
@Test // DATAJPA-352
@SuppressWarnings("unchecked")
void validatesAndRejectsCountQueryIfPagingMethod() throws Exception {
Method method = SampleRepository.class.getMethod("pageByAnnotatedQuery", Pageable.class);
when(em.createQuery(Mockito.contains("count"))).thenThrow(IllegalArgumentException.class);
assertThatIllegalArgumentException().isThrownBy(() -> createJpaQuery(method)).withMessageContaining("Count")
assertThatIllegalArgumentException() //
.isThrownBy(() -> createJpaQuery(method)) //
.withMessageContaining("Count") //
.withMessageContaining(method.getName());
}

Loading…
Cancel
Save