From e4a2416b845df21e2aadada19a5a4ad59bd91f72 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Mon, 9 Dec 2024 14:25:53 +0100 Subject: [PATCH] Refine NamedQuery error messages when using Sort/Pageable parameters. Closes #3660 --- .../jpa/repository/query/JpaQueryMethod.java | 15 ++----------- .../data/jpa/repository/query/NamedQuery.java | 21 +++++++++++-------- .../JpaQueryLookupStrategyUnitTests.java | 2 +- 3 files changed, 15 insertions(+), 23 deletions(-) diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java index 885b989bbe..ab2cd777ef 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java @@ -22,7 +22,6 @@ import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collections; -import java.util.HashSet; import java.util.List; import java.util.Optional; import java.util.Set; @@ -70,20 +69,10 @@ public class JpaQueryMethod extends QueryMethod { * Persistence Specification: Persistent Fields and Properties - Paragraph starting with * "Collection-valued persistent...". */ - private static final Set> NATIVE_ARRAY_TYPES; + private static final Set> NATIVE_ARRAY_TYPES = Set.of(byte[].class, Byte[].class, char[].class, + Character[].class); private static final StoredProcedureAttributeSource storedProcedureAttributeSource = StoredProcedureAttributeSource.INSTANCE; - static { - - Set> types = new HashSet<>(); - types.add(byte[].class); - types.add(Byte[].class); - types.add(char[].class); - types.add(Character[].class); - - NATIVE_ARRAY_TYPES = Collections.unmodifiableSet(types); - } - private final QueryExtractor extractor; private final Method method; private final Class returnType; diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/NamedQuery.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/NamedQuery.java index 659c04c7de..bfa635b413 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/NamedQuery.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/NamedQuery.java @@ -69,8 +69,9 @@ private NamedQuery(JpaQueryMethod method, EntityManager em) { Parameters parameters = method.getParameters(); if (parameters.hasSortParameter()) { - throw new IllegalStateException(String.format("Finder method %s is backed by a NamedQuery and must " - + "not contain a sort parameter as we cannot modify the query; Use @Query instead", method)); + throw new IllegalStateException(String.format("Query method %s is backed by a NamedQuery and must " + + "not contain a sort parameter as we cannot modify the query; Use @%s(value=…) instead to apply sorting or remove the 'Sort' parameter.", + method, method.isNativeQuery() ? "NativeQuery" : "Query")); } this.namedCountQueryIsPresent = hasNamedQuery(em, countQueryName); @@ -85,14 +86,14 @@ private NamedQuery(JpaQueryMethod method, EntityManager em) { if (parameters.hasPageableParameter()) { LOG.warn(String.format( - "Finder method %s is backed by a NamedQuery but contains a Pageable parameter; Sorting delivered via this Pageable will not be applied", - method)); + "Query method %s is backed by a NamedQuery but contains a Pageable parameter; Sorting delivered via this Pageable will not be applied; Use @%s(value=…) instead to apply sorting.", + method, method.isNativeQuery() ? "NativeQuery" : "Query")); } String queryString = extractor.extractQueryString(query); - // TODO: Detect whether a named query is a native one. - this.declaredQuery = Lazy.of(() -> DeclaredQuery.of(queryString, query.toString().contains("NativeQuery"))); + this.declaredQuery = Lazy + .of(() -> DeclaredQuery.of(queryString, method.isNativeQuery() || query.toString().contains("NativeQuery"))); this.metadataCache = new QueryParameterSetter.QueryMetadataCache(); } @@ -133,7 +134,7 @@ public static RepositoryQuery lookupFrom(JpaQueryMethod method, EntityManager em String queryName = method.getNamedQueryName(); if (LOG.isDebugEnabled()) { - LOG.debug(String.format("Looking up named query %s", queryName)); + LOG.debug(String.format("Looking up named query '%s'", queryName)); } if (!hasNamedQuery(em, queryName)) { @@ -141,12 +142,14 @@ public static RepositoryQuery lookupFrom(JpaQueryMethod method, EntityManager em } if (method.isScrollQuery()) { - throw QueryCreationException.create(method, "Scroll queries are not supported using String-based queries"); + throw QueryCreationException.create(method, String.format( + "Scroll queries are not supported using String-based queries as we cannot rewrite the query string. Use @%s(value=…) instead.", + method.isNativeQuery() ? "NativeQuery" : "Query")); } RepositoryQuery query = new NamedQuery(method, em); if (LOG.isDebugEnabled()) { - LOG.debug(String.format("Found named query %s", queryName)); + LOG.debug(String.format("Found named query '%s'", queryName)); } return query; } diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryLookupStrategyUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryLookupStrategyUnitTests.java index 7a27c1bfc6..cff7fc83c6 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryLookupStrategyUnitTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryLookupStrategyUnitTests.java @@ -163,7 +163,7 @@ void namedQueryWithSortShouldThrowIllegalStateException() throws NoSuchMethodExc assertThatIllegalStateException() .isThrownBy(() -> strategy.resolveQuery(method, metadata, projectionFactory, namedQueries)) .withMessageContaining( - "is backed by a NamedQuery and must not contain a sort parameter as we cannot modify the query; Use @Query instead"); + "is backed by a NamedQuery and must not contain a sort parameter as we cannot modify the query; Use @Query(value=…) instead to apply sorting or remove the 'Sort' parameter."); } @Test // GH-2018