diff --git a/pom.xml b/pom.xml
index dd2134e5d1..d86598d842 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
org.springframework.data
spring-data-jpa-parent
- 3.2.0-SNAPSHOT
+ 3.2.0-gh-2989-SNAPSHOT
pom
Spring Data JPA Parent
diff --git a/spring-data-envers/pom.xml b/spring-data-envers/pom.xml
index f239d6394b..70ab172953 100755
--- a/spring-data-envers/pom.xml
+++ b/spring-data-envers/pom.xml
@@ -5,12 +5,12 @@
org.springframework.data
spring-data-envers
- 3.2.0-SNAPSHOT
+ 3.2.0-gh-2989-SNAPSHOT
org.springframework.data
spring-data-jpa-parent
- 3.2.0-SNAPSHOT
+ 3.2.0-gh-2989-SNAPSHOT
../pom.xml
diff --git a/spring-data-jpa-distribution/pom.xml b/spring-data-jpa-distribution/pom.xml
index a458953182..36d9fadf38 100644
--- a/spring-data-jpa-distribution/pom.xml
+++ b/spring-data-jpa-distribution/pom.xml
@@ -14,7 +14,7 @@
org.springframework.data
spring-data-jpa-parent
- 3.2.0-SNAPSHOT
+ 3.2.0-gh-2989-SNAPSHOT
../pom.xml
diff --git a/spring-data-jpa/pom.xml b/spring-data-jpa/pom.xml
index b21b03c313..e0964095ca 100644
--- a/spring-data-jpa/pom.xml
+++ b/spring-data-jpa/pom.xml
@@ -6,7 +6,7 @@
org.springframework.data
spring-data-jpa
- 3.2.0-SNAPSHOT
+ 3.2.0-gh-2989-SNAPSHOT
Spring Data JPA
Spring Data module for JPA repositories.
@@ -15,7 +15,7 @@
org.springframework.data
spring-data-jpa-parent
- 3.2.0-SNAPSHOT
+ 3.2.0-gh-2989-SNAPSHOT
../pom.xml
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/Query.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/Query.java
index d626507f24..d762b41bd7 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/Query.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/Query.java
@@ -22,6 +22,7 @@
import java.lang.annotation.Target;
import org.springframework.data.annotation.QueryAnnotation;
+import org.springframework.data.jpa.repository.query.QueryEnhancerOption;
/**
* Annotation to declare finder queries directly on repository methods.
@@ -86,4 +87,12 @@
* @since 3.0
*/
Class extends QueryRewriter> queryRewriter() default QueryRewriter.IdentityQueryRewriter.class;
+
+ /**
+ * For native queries, indicate whether or not to skip the JSqlParser.
+ *
+ * @return
+ * @since 3.2
+ */
+ QueryEnhancerOption queryEnhancerOption() default QueryEnhancerOption.AUTOMATIC_BEST_FIT;
}
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQuery.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQuery.java
index cf22cc9f40..44a5ba2d2e 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQuery.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQuery.java
@@ -75,7 +75,7 @@ public AbstractStringBasedJpaQuery(JpaQueryMethod method, EntityManager em, Stri
this.evaluationContextProvider = evaluationContextProvider;
this.query = new ExpressionBasedStringQuery(queryString, method.getEntityInformation(), parser,
- method.isNativeQuery());
+ method.isNativeQuery(), method.queryEnhancerOption());
this.countQuery = Lazy.of(() -> {
DeclaredQuery countQuery = query.deriveCountQuery(countQueryString, method.getCountQueryProjection());
@@ -92,7 +92,7 @@ public AbstractStringBasedJpaQuery(JpaQueryMethod method, EntityManager em, Stri
@Override
public Query doCreateQuery(JpaParametersParameterAccessor accessor) {
- String sortedQueryString = QueryEnhancerFactory.forQuery(query) //
+ String sortedQueryString = query.queryEnhancerOption().forQuery(query) //
.applySorting(accessor.getSort(), query.getAlias());
ResultProcessor processor = getQueryMethod().getResultProcessor().withDynamicProjection(accessor);
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/DeclaredQuery.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/DeclaredQuery.java
index 670e030fb2..32c83c944a 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/DeclaredQuery.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/DeclaredQuery.java
@@ -111,4 +111,8 @@ default boolean usesPaging() {
default boolean isNativeQuery() {
return false;
}
+
+ default QueryEnhancerOption queryEnhancerOption() {
+ return QueryEnhancerOption.AUTOMATIC_BEST_FIT;
+ }
}
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQuery.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQuery.java
index 3bee9c2d48..bcad881564 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQuery.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQuery.java
@@ -59,9 +59,15 @@ class ExpressionBasedStringQuery extends StringQuery {
* @param parser must not be {@literal null}.
* @param nativeQuery is a given query is native or not
*/
+ public ExpressionBasedStringQuery(String query, JpaEntityMetadata> metadata, SpelExpressionParser parser,
+ boolean nativeQuery, QueryEnhancerOption queryEnhancerOption) {
+ super(renderQueryIfExpressionOrReturnQuery(query, metadata, parser), nativeQuery && !containsExpression(query),
+ queryEnhancerOption);
+ }
+
public ExpressionBasedStringQuery(String query, JpaEntityMetadata> metadata, SpelExpressionParser parser,
boolean nativeQuery) {
- super(renderQueryIfExpressionOrReturnQuery(query, metadata, parser), nativeQuery && !containsExpression(query));
+ this(query, metadata, parser, nativeQuery, QueryEnhancerOption.AUTOMATIC_BEST_FIT);
}
/**
@@ -75,7 +81,7 @@ public ExpressionBasedStringQuery(String query, JpaEntityMetadata> metadata, S
*/
static ExpressionBasedStringQuery from(DeclaredQuery query, JpaEntityMetadata> metadata,
SpelExpressionParser parser, boolean nativeQuery) {
- return new ExpressionBasedStringQuery(query.getQueryString(), metadata, parser, nativeQuery);
+ return new ExpressionBasedStringQuery(query.getQueryString(), metadata, parser, nativeQuery, query.queryEnhancerOption());
}
/**
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 ed566ba52c..9894f369ab 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
@@ -94,6 +94,7 @@ public class JpaQueryMethod extends QueryMethod {
private final Lazy jpaEntityGraph;
private final Lazy modifying;
private final Lazy isNativeQuery;
+ private final Lazy queryEnhancerOption;
private final Lazy isCollectionQuery;
private final Lazy isProcedureQuery;
private final Lazy> entityMetadata;
@@ -136,6 +137,7 @@ protected JpaQueryMethod(Method method, RepositoryMetadata metadata, ProjectionF
return new JpaEntityGraph(entityGraph, getNamedQueryName());
});
this.isNativeQuery = Lazy.of(() -> getAnnotationValue("nativeQuery", Boolean.class));
+ this.queryEnhancerOption = Lazy.of(() -> getAnnotationValue("queryEnhancerOption", QueryEnhancerOption.class));
this.isCollectionQuery = Lazy.of(() -> super.isCollectionQuery() && !NATIVE_ARRAY_TYPES.contains(this.returnType));
this.isProcedureQuery = Lazy.of(() -> AnnotationUtils.findAnnotation(method, Procedure.class) != null);
this.entityMetadata = Lazy.of(() -> new DefaultJpaEntityMetadata<>(getDomainClass()));
@@ -387,6 +389,10 @@ boolean isNativeQuery() {
return this.isNativeQuery.get();
}
+ QueryEnhancerOption queryEnhancerOption() {
+ return this.queryEnhancerOption.get();
+ }
+
@Override
public String getNamedQueryName() {
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryEnhancerFactory.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryEnhancerFactory.java
index 74aa77e611..62a26b1d8e 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryEnhancerFactory.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryEnhancerFactory.java
@@ -15,10 +15,6 @@
*/
package org.springframework.data.jpa.repository.query;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.util.ClassUtils;
-
/**
* Encapsulates different strategies for the creation of a {@link QueryEnhancer} from a {@link DeclaredQuery}.
*
@@ -29,48 +25,35 @@
*/
public final class QueryEnhancerFactory {
- private static final Log LOG = LogFactory.getLog(QueryEnhancerFactory.class);
-
- private static final boolean jSqlParserPresent = ClassUtils.isPresent("net.sf.jsqlparser.parser.JSqlParser",
- QueryEnhancerFactory.class.getClassLoader());
-
- private static final boolean hibernatePresent = ClassUtils.isPresent("org.hibernate.query.TypedParameterValue",
- QueryEnhancerFactory.class.getClassLoader());
-
- static {
-
- if (jSqlParserPresent) {
- LOG.info("JSqlParser is in classpath; If applicable, JSqlParser will be used");
- }
-
- if (hibernatePresent) {
- LOG.info("Hibernate is in classpath; If applicable, HQL parser will be used.");
- }
- }
-
- private QueryEnhancerFactory() {}
-
- /**
- * Creates a new {@link QueryEnhancer} for the given {@link DeclaredQuery}.
- *
- * @param query must not be {@literal null}.
- * @return an implementation of {@link QueryEnhancer} that suits the query the most
- */
- public static QueryEnhancer forQuery(DeclaredQuery query) {
-
- if (query.isNativeQuery()) {
-
- if (jSqlParserPresent) {
- /*
- * If JSqlParser fails, throw some alert signaling that people should write a custom Impl.
- */
- return new JSqlParserQueryEnhancer(query);
- }
-
- return new DefaultQueryEnhancer(query);
- }
-
- return hibernatePresent ? JpaQueryEnhancer.forHql(query) : JpaQueryEnhancer.forJpql(query);
- }
+ // private static final Log LOG = LogFactory.getLog(QueryEnhancerFactory.class);
+ //
+ // private static final boolean jSqlParserPresent = ClassUtils.isPresent("net.sf.jsqlparser.parser.JSqlParser",
+ // QueryEnhancerFactory.class.getClassLoader());
+ //
+ // private static final boolean hibernatePresent = ClassUtils.isPresent("org.hibernate.query.TypedParameterValue",
+ // QueryEnhancerFactory.class.getClassLoader());
+ //
+ // static {
+ //
+ // if (jSqlParserPresent) {
+ // LOG.info("JSqlParser is in classpath; If applicable, JSqlParser will be used");
+ // }
+ //
+ // if (hibernatePresent) {
+ // LOG.info("Hibernate is in classpath; If applicable, HQL parser will be used.");
+ // }
+ // }
+ //
+ // private QueryEnhancerFactory() {}
+ //
+ // /**
+ // * Creates a new {@link QueryEnhancer} for the given {@link DeclaredQuery}.
+ // *
+ // * @param query must not be {@literal null}.
+ // * @return an implementation of {@link QueryEnhancer} that suits the query the most
+ // */
+ // public static QueryEnhancer forQuery(DeclaredQuery query) {
+ // return QueryEnhancerOption.DEFAULT.forQuery(query);
+ // }
}
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryEnhancerOption.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryEnhancerOption.java
new file mode 100644
index 0000000000..19df27376d
--- /dev/null
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryEnhancerOption.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2022-2023 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.jpa.repository.query;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.util.ClassUtils;
+
+/**
+ * Encapsulates different strategies for the creation of a {@link QueryEnhancer} from a {@link DeclaredQuery}.
+ *
+ * @author Diego Krupitza
+ * @author Greg Turnquist
+ * @author Mark Paluch
+ * @since 3.2.0
+ */
+public enum QueryEnhancerOption implements QueryEnhancerStrategy {
+
+ /**
+ * Automatically pick the best fit based on availability of JSqlParser and Hibernate.
+ */
+ AUTOMATIC_BEST_FIT {
+ @Override
+ public QueryEnhancer forQuery(DeclaredQuery query) {
+
+ if (query.isNativeQuery()) {
+
+ if (jSqlParserPresent) {
+ /*
+ * If JSqlParser fails, throw some alert signaling that people should write a custom Impl.
+ */
+ return new JSqlParserQueryEnhancer(query);
+ }
+
+ return new DefaultQueryEnhancer(query);
+ }
+
+ return hibernatePresent ? JpaQueryEnhancer.forHql(query) : JpaQueryEnhancer.forJpql(query);
+ }
+ },
+
+ /**
+ * Automatically pick the best fit based on availability of Hibernate. NOTE: JSqlParser is not
+ * considered, even if it's on the classpath.
+ */
+ AUTOMATIC_BEST_FIT_WITHOUT_JSQL {
+ @Override
+ public QueryEnhancer forQuery(DeclaredQuery query) {
+
+ if (query.isNativeQuery()) {
+
+ LOG.warn("We are NOT evaluating if JSqlParser is on the classpath in order to handle '" + query.getQueryString()
+ + "'");
+
+ return new DefaultQueryEnhancer(query);
+ }
+
+ return hibernatePresent ? JpaQueryEnhancer.forHql(query) : JpaQueryEnhancer.forJpql(query);
+ }
+ },
+
+ MANUAL_HIBERNATE {
+ @Override
+ public QueryEnhancer forQuery(DeclaredQuery query) {
+
+ LOG.warn("You have chosen HIBERNATE to handle '" + query.getQueryString() + "'");
+
+ return JpaQueryEnhancer.forHql(query);
+ }
+ },
+
+ MANUAL_JPA {
+ @Override
+ public QueryEnhancer forQuery(DeclaredQuery query) {
+
+ LOG.warn("You have chose JPA to handle '" + query.getQueryString() + "'");
+
+ return JpaQueryEnhancer.forJpql(query);
+ }
+ };
+
+ private static final Log LOG = LogFactory.getLog(QueryEnhancerFactory.class);
+
+ private static final boolean jSqlParserPresent = ClassUtils.isPresent("net.sf.jsqlparser.parser.JSqlParser",
+ QueryEnhancerOption.class.getClassLoader());
+
+ private static final boolean hibernatePresent = ClassUtils.isPresent("org.hibernate.query.TypedParameterValue",
+ QueryEnhancerOption.class.getClassLoader());
+
+ static {
+
+ if (jSqlParserPresent) {
+ LOG.info("JSqlParser is in classpath; If applicable, JSqlParser will be used");
+ }
+
+ if (hibernatePresent) {
+ LOG.info("Hibernate is in classpath; If applicable, HQL parser will be used.");
+ }
+ }
+}
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryEnhancerStrategy.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryEnhancerStrategy.java
new file mode 100644
index 0000000000..4d723aa40c
--- /dev/null
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryEnhancerStrategy.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2022-2023 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.jpa.repository.query;
+
+/**
+ * Defines the contract for extracting a {@link QueryEnhancer} from a {@link DeclaredQuery}.
+ *
+ * @author Greg Turnquist
+ * @since 3.2
+ */
+public interface QueryEnhancerStrategy {
+
+ QueryEnhancer forQuery(DeclaredQuery query);
+
+}
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/StringQuery.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/StringQuery.java
index afa68ff51c..baa40b8907 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/StringQuery.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/StringQuery.java
@@ -65,6 +65,7 @@ class StringQuery implements DeclaredQuery {
private final boolean containsPageableInSpel;
private final boolean usesJdbcStyleParameters;
private final boolean isNative;
+ private final QueryEnhancerOption queryEnhancerOption;
private final QueryEnhancer queryEnhancer;
/**
@@ -73,11 +74,12 @@ class StringQuery implements DeclaredQuery {
* @param query must not be {@literal null} or empty.
*/
@SuppressWarnings("deprecation")
- StringQuery(String query, boolean isNative) {
+ StringQuery(String query, boolean isNative, QueryEnhancerOption queryEnhancerOption) {
Assert.hasText(query, "Query must not be null or empty");
this.isNative = isNative;
+ this.queryEnhancerOption = queryEnhancerOption;
this.bindings = new ArrayList<>();
this.containsPageableInSpel = query.contains("#pageable");
@@ -87,11 +89,15 @@ class StringQuery implements DeclaredQuery {
this.usesJdbcStyleParameters = queryMeta.usesJdbcStyleParameters;
- this.queryEnhancer = QueryEnhancerFactory.forQuery(this);
+ this.queryEnhancer = queryEnhancerOption.forQuery(this);
this.alias = this.queryEnhancer.detectAlias();
this.hasConstructorExpression = this.queryEnhancer.hasConstructorExpression();
}
+ StringQuery(String query, boolean isNative) {
+ this(query, isNative, QueryEnhancerOption.AUTOMATIC_BEST_FIT);
+ }
+
/**
* Returns whether we have found some like bindings.
*/
@@ -157,6 +163,11 @@ public boolean isNativeQuery() {
return isNative;
}
+ @Override
+ public QueryEnhancerOption queryEnhancerOption() {
+ return queryEnhancerOption;
+ }
+
/**
* A parser that extracts the parameter bindings from a given query string.
*
@@ -279,7 +290,6 @@ private String parseParameterBindingsOfQueryIntoBindingsAndReturnCleanedQuery(St
parameterIndex = expressionParameterIndex;
}
-
BindingIdentifier queryParameter;
if (parameterIndex != null) {
queryParameter = BindingIdentifier.of(parameterIndex);
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java
index 9264185849..5800f65f8e 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java
@@ -2914,6 +2914,19 @@ void supportsProjectionsWithNativeQueries() {
assertThat(result.getLastname()).isEqualTo(user.getLastname());
}
+ @Test // GH-2989
+ void supportsProjectionsWithNativeQueriesSkippingJSql() {
+
+ flushTestUsers();
+
+ User user = repository.findAll().get(0);
+
+ NameOnly result = repository.findByNativeQueryWithNoJSql(user.getId());
+
+ assertThat(result.getFirstname()).isEqualTo(user.getFirstname());
+ assertThat(result.getLastname()).isEqualTo(user.getLastname());
+ }
+
@Test // DATAJPA-1248
void supportsProjectionsWithNativeQueriesAndCamelCaseProperty() {
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JSqlParserQueryEnhancerUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JSqlParserQueryEnhancerUnitTests.java
index 2f84a4c1e1..008531bc43 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JSqlParserQueryEnhancerUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JSqlParserQueryEnhancerUnitTests.java
@@ -61,7 +61,7 @@ void setOperationListWorks() {
+ "select SOME_COLUMN from SOME_OTHER_TABLE where REPORTING_DATE = :REPORTING_DATE";
StringQuery stringQuery = new StringQuery(setQuery, true);
- QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(stringQuery);
+ QueryEnhancer queryEnhancer = stringQuery.queryEnhancerOption().forQuery(stringQuery);
assertThat(stringQuery.getAlias()).isNullOrEmpty();
assertThat(stringQuery.getProjection()).isEqualToIgnoringCase("SOME_COLUMN");
@@ -84,7 +84,7 @@ void complexSetOperationListWorks() {
+ "union select SOME_COLUMN from SOME_OTHER_OTHER_TABLE";
StringQuery stringQuery = new StringQuery(setQuery, true);
- QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(stringQuery);
+ QueryEnhancer queryEnhancer = stringQuery.queryEnhancerOption().forQuery(stringQuery);
assertThat(stringQuery.getAlias()).isNullOrEmpty();
assertThat(stringQuery.getProjection()).isEqualToIgnoringCase("SOME_COLUMN");
@@ -111,7 +111,7 @@ void deeplyNestedcomplexSetOperationListWorks() {
+ "\t;";
StringQuery stringQuery = new StringQuery(setQuery, true);
- QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(stringQuery);
+ QueryEnhancer queryEnhancer = stringQuery.queryEnhancerOption().forQuery(stringQuery);
assertThat(stringQuery.getAlias()).isNullOrEmpty();
assertThat(stringQuery.getProjection()).isEqualToIgnoringCase("CustomerID");
@@ -131,7 +131,7 @@ void valuesStatementsWorks() {
String setQuery = "VALUES (1, 2, 'test')";
StringQuery stringQuery = new StringQuery(setQuery, true);
- QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(stringQuery);
+ QueryEnhancer queryEnhancer = stringQuery.queryEnhancerOption().forQuery(stringQuery);
assertThat(stringQuery.getAlias()).isNullOrEmpty();
assertThat(stringQuery.getProjection()).isNullOrEmpty();
@@ -152,7 +152,7 @@ void withStatementsWorks() {
+ "select day, value from sample_data as a";
StringQuery stringQuery = new StringQuery(setQuery, true);
- QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(stringQuery);
+ QueryEnhancer queryEnhancer = stringQuery.queryEnhancerOption().forQuery(stringQuery);
assertThat(stringQuery.getAlias()).isEqualToIgnoringCase("a");
assertThat(stringQuery.getProjection()).isEqualToIgnoringCase("day, value");
@@ -175,7 +175,7 @@ void multipleWithStatementsWorks() {
+ "select day, value from sample_data as a";
StringQuery stringQuery = new StringQuery(setQuery, true);
- QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(stringQuery);
+ QueryEnhancer queryEnhancer = stringQuery.queryEnhancerOption().forQuery(stringQuery);
assertThat(stringQuery.getAlias()).isEqualToIgnoringCase("a");
assertThat(stringQuery.getProjection()).isEqualToIgnoringCase("day, value");
@@ -195,7 +195,7 @@ void multipleWithStatementsWorks() {
void truncateStatementShouldWork() {
StringQuery stringQuery = new StringQuery("TRUNCATE TABLE foo", true);
- QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(stringQuery);
+ QueryEnhancer queryEnhancer = stringQuery.queryEnhancerOption().forQuery(stringQuery);
assertThat(stringQuery.getAlias()).isNull();
assertThat(stringQuery.getProjection()).isEmpty();
@@ -213,7 +213,7 @@ void truncateStatementShouldWork() {
void mergeStatementWorksWithJSqlParser(String query, String alias) {
StringQuery stringQuery = new StringQuery(query, true);
- QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(stringQuery);
+ QueryEnhancer queryEnhancer = stringQuery.queryEnhancerOption().forQuery(stringQuery);
assertThat(queryEnhancer.detectAlias()).isEqualTo(alias);
assertThat(QueryUtils.detectAlias(query)).isNull();
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerFactoryUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerFactoryUnitTests.java
index ef90549fd4..b2b4869a23 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerFactoryUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerFactoryUnitTests.java
@@ -32,7 +32,7 @@ void createsParsingImplementationForNonNativeQuery() {
StringQuery query = new StringQuery("select new com.example.User(u.firstname) from User u", false);
- QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(query);
+ QueryEnhancer queryEnhancer = query.queryEnhancerOption().forQuery(query);
assertThat(queryEnhancer) //
.isInstanceOf(JpaQueryEnhancer.class);
@@ -47,7 +47,7 @@ void createsJSqlImplementationForNativeQuery() {
StringQuery query = new StringQuery("select * from User", true);
- QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(query);
+ QueryEnhancer queryEnhancer = query.queryEnhancerOption().forQuery(query);
assertThat(queryEnhancer) //
.isInstanceOf(JSqlParserQueryEnhancer.class);
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerUnitTests.java
index 6140b313bf..598791eca3 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerUnitTests.java
@@ -622,7 +622,17 @@ void modifyingQueriesAreDetectedCorrectly() {
assertThat(modiQuery.hasConstructorExpression()).isEqualTo(constructorExpressionNotConsideringQueryType);
assertThat(countQueryForNotConsiderQueryType).isEqualToIgnoringCase(modifyingQuery);
- assertThat(QueryEnhancerFactory.forQuery(modiQuery).createCountQueryFor()).isEqualToIgnoringCase(modifyingQuery);
+ assertThat(modiQuery.queryEnhancerOption().forQuery(modiQuery).createCountQueryFor())
+ .isEqualToIgnoringCase(modifyingQuery);
+ }
+
+ @Test // GH-2989
+ void skippingJSqlShouldRevertToDefaultQueryEnhancer() {
+
+ assertThat(getEnhancer(new StringQuery(QUERY, true, QueryEnhancerOption.AUTOMATIC_BEST_FIT)))
+ .isInstanceOf(JSqlParserQueryEnhancer.class);
+ assertThat(getEnhancer(new StringQuery(QUERY, true, QueryEnhancerOption.AUTOMATIC_BEST_FIT_WITHOUT_JSQL)))
+ .isInstanceOf(DefaultQueryEnhancer.class);
}
@ParameterizedTest // GH-2593
@@ -630,7 +640,7 @@ void modifyingQueriesAreDetectedCorrectly() {
void insertStatementIsProcessedSameAsDefault(String insertQuery) {
StringQuery stringQuery = new StringQuery(insertQuery, true);
- QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(stringQuery);
+ QueryEnhancer queryEnhancer = stringQuery.queryEnhancerOption().forQuery(stringQuery);
Sort sorting = Sort.by("day").descending();
@@ -686,7 +696,7 @@ private static void assertCountQuery(StringQuery originalQuery, String countQuer
}
private static QueryEnhancer getEnhancer(DeclaredQuery query) {
- return QueryEnhancerFactory.forQuery(query);
+ return query.queryEnhancerOption().forQuery(query);
}
}
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/UserRepository.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/UserRepository.java
index c9a342538f..2288801d88 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/UserRepository.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/UserRepository.java
@@ -44,6 +44,7 @@
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.jpa.repository.QueryHints;
import org.springframework.data.jpa.repository.query.Procedure;
+import org.springframework.data.jpa.repository.query.QueryEnhancerOption;
import org.springframework.data.querydsl.ListQuerydslPredicateExecutor;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
@@ -585,6 +586,11 @@ List findUsersByFirstnameForSpELExpressionWithParameterIndexOnlyWithEntity
@Query(value = "SELECT firstname, lastname FROM SD_User WHERE id = ?1", nativeQuery = true)
NameOnly findByNativeQuery(Integer id);
+ // GH-2989
+ @Query(value = "SELECT firstname, lastname FROM SD_User WHERE id = ?1", nativeQuery = true,
+ queryEnhancerOption = QueryEnhancerOption.AUTOMATIC_BEST_FIT_WITHOUT_JSQL)
+ NameOnly findByNativeQueryWithNoJSql(Integer id);
+
// DATAJPA-1248
@Query(value = "SELECT emailaddress FROM SD_User WHERE id = ?1", nativeQuery = true)
EmailOnly findEmailOnlyByNativeQuery(Integer id);