From f43cd80f76e16403bb7f1a574f3fca8183f7cfa3 Mon Sep 17 00:00:00 2001 From: Oliver Drotbohm Date: Wed, 21 Dec 2022 22:21:14 +0100 Subject: [PATCH] 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. Related ticket: #2736. --- .../jpa/repository/query/SimpleJpaQuery.java | 33 ++++++++++--------- .../query/SimpleJpaQueryUnitTests.java | 6 ++-- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/SimpleJpaQuery.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/SimpleJpaQuery.java index c2e23738d5..285aaf7654 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/SimpleJpaQuery.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/SimpleJpaQuery.java @@ -41,14 +41,16 @@ 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 evaluationContextProvider must not be {@literal null} * @param parser must not be {@literal null} */ - public SimpleJpaQuery(JpaQueryMethod method, EntityManager em, @Nullable String countQueryString, - QueryRewriter queryRewriter, QueryMethodEvaluationContextProvider evaluationContextProvider, SpelExpressionParser parser) { - this(method, em, method.getRequiredAnnotatedQuery(), countQueryString, queryRewriter, evaluationContextProvider, parser); + public SimpleJpaQuery(JpaQueryMethod method, EntityManager em, @Nullable String sourceQuery, + QueryRewriter queryRewriter, QueryMethodEvaluationContextProvider evaluationContextProvider, + SpelExpressionParser parser) { + this(method, em, method.getRequiredAnnotatedQuery(), sourceQuery, queryRewriter, evaluationContextProvider, + parser); } /** @@ -56,22 +58,22 @@ public SimpleJpaQuery(JpaQueryMethod method, EntityManager em, @Nullable String * * @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 evaluationContextProvider must not be {@literal null} * @param parser must not be {@literal null} */ - public SimpleJpaQuery(JpaQueryMethod method, EntityManager em, String queryString, @Nullable String countQueryString, QueryRewriter queryRewriter, - QueryMethodEvaluationContextProvider evaluationContextProvider, SpelExpressionParser parser) { + public SimpleJpaQuery(JpaQueryMethod method, EntityManager em, String sourceQuery, @Nullable String countQueryString, + QueryRewriter queryRewriter, QueryMethodEvaluationContextProvider evaluationContextProvider, + SpelExpressionParser parser) { - super(method, em, queryString, countQueryString, queryRewriter, evaluationContextProvider, parser); + super(method, em, sourceQuery, countQueryString, queryRewriter, evaluationContextProvider, parser); - 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); } } @@ -81,23 +83,24 @@ public SimpleJpaQuery(JpaQueryMethod method, EntityManager em, String queryStrin * @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 { diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/SimpleJpaQueryUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/SimpleJpaQueryUnitTests.java index 8ebb5a4e8c..971dc50626 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/SimpleJpaQueryUnitTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/SimpleJpaQueryUnitTests.java @@ -37,7 +37,6 @@ 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; @@ -175,14 +174,15 @@ void doesNotValidateCountQueryIfNotPagingMethod() throws Exception { } @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()); }