Skip to content

Introduce flag to disable JSqlParser for a given query. #3148

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa-parent</artifactId>
<version>3.2.0-SNAPSHOT</version>
<version>3.2.0-gh-2989-SNAPSHOT</version>
<packaging>pom</packaging>

<name>Spring Data JPA Parent</name>
Expand Down
4 changes: 2 additions & 2 deletions spring-data-envers/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-envers</artifactId>
<version>3.2.0-SNAPSHOT</version>
<version>3.2.0-gh-2989-SNAPSHOT</version>

<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa-parent</artifactId>
<version>3.2.0-SNAPSHOT</version>
<version>3.2.0-gh-2989-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
2 changes: 1 addition & 1 deletion spring-data-jpa-distribution/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa-parent</artifactId>
<version>3.2.0-SNAPSHOT</version>
<version>3.2.0-gh-2989-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
4 changes: 2 additions & 2 deletions spring-data-jpa/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>3.2.0-SNAPSHOT</version>
<version>3.2.0-gh-2989-SNAPSHOT</version>

<name>Spring Data JPA</name>
<description>Spring Data module for JPA repositories.</description>
Expand All @@ -15,7 +15,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa-parent</artifactId>
<version>3.2.0-SNAPSHOT</version>
<version>3.2.0-gh-2989-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand All @@ -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);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,8 @@ default boolean usesPaging() {
default boolean isNativeQuery() {
return false;
}

default QueryEnhancerOption queryEnhancerOption() {
return QueryEnhancerOption.AUTOMATIC_BEST_FIT;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

/**
Expand All @@ -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());
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ public class JpaQueryMethod extends QueryMethod {
private final Lazy<JpaEntityGraph> jpaEntityGraph;
private final Lazy<Modifying> modifying;
private final Lazy<Boolean> isNativeQuery;
private final Lazy<QueryEnhancerOption> queryEnhancerOption;
private final Lazy<Boolean> isCollectionQuery;
private final Lazy<Boolean> isProcedureQuery;
private final Lazy<JpaEntityMetadata<?>> entityMetadata;
Expand Down Expand Up @@ -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()));
Expand Down Expand Up @@ -387,6 +389,10 @@ boolean isNativeQuery() {
return this.isNativeQuery.get();
}

QueryEnhancerOption queryEnhancerOption() {
return this.queryEnhancerOption.get();
}

@Override
public String getNamedQueryName() {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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}.
*
Expand All @@ -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);
// }

}
Original file line number Diff line number Diff line change
@@ -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 <strong>not</strong>
* 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.");
}
}
}
Original file line number Diff line number Diff line change
@@ -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);

}
Loading