Skip to content

Commit ff92e85

Browse files
committed
Polishing.
Avoid unconditional ConcurrentLruCache instances for each String-based query. See: #3310 Original pull request: #3321
1 parent f66e185 commit ff92e85

File tree

3 files changed

+63
-14
lines changed

3 files changed

+63
-14
lines changed

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

+48-10
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ abstract class AbstractStringBasedJpaQuery extends AbstractJpaQuery {
5454
private final SpelExpressionParser parser;
5555
private final QueryParameterSetter.QueryMetadataCache metadataCache = new QueryParameterSetter.QueryMetadataCache();
5656
private final QueryRewriter queryRewriter;
57-
private ConcurrentLruCache<CachableQuery, String> queryCache = new ConcurrentLruCache<>(16, this::applySorting);
57+
private final QuerySortRewriter querySortRewriter;
5858
private final Lazy<ParameterBinder> countParameterBinder;
5959

6060
/**
@@ -102,6 +102,13 @@ public AbstractStringBasedJpaQuery(JpaQueryMethod method, EntityManager em, Stri
102102
this.parser = parser;
103103
this.queryRewriter = queryRewriter;
104104

105+
JpaParameters parameters = method.getParameters();
106+
if (parameters.hasPageableParameter() || parameters.hasSortParameter()) {
107+
this.querySortRewriter = new CachingQuerySortRewriter();
108+
} else {
109+
this.querySortRewriter = NoOpQuerySortRewriter.INSTANCE;
110+
}
111+
105112
Assert.isTrue(method.isNativeQuery() || !query.usesJdbcStyleParameters(),
106113
"JDBC style parameters (?) are not supported for JPA queries");
107114
}
@@ -110,7 +117,7 @@ public AbstractStringBasedJpaQuery(JpaQueryMethod method, EntityManager em, Stri
110117
public Query doCreateQuery(JpaParametersParameterAccessor accessor) {
111118

112119
Sort sort = accessor.getSort();
113-
String sortedQueryString = applySortingIfNecessary(query, sort);
120+
String sortedQueryString = querySortRewriter.getSorted(query, sort);
114121

115122
ResultProcessor processor = getQueryMethod().getResultProcessor().withDynamicProjection(accessor);
116123

@@ -123,10 +130,6 @@ public Query doCreateQuery(JpaParametersParameterAccessor accessor) {
123130
return parameterBinder.get().bindAndPrepare(query, metadata, accessor);
124131
}
125132

126-
protected String applySorting(DeclaredQuery query, Sort sort) {
127-
return queryCache.get(new CachableQuery(query, sort));
128-
}
129-
130133
@Override
131134
protected ParameterBinder createBinder() {
132135
return createBinder(query);
@@ -210,12 +213,46 @@ String applySorting(CachableQuery cachableQuery) {
210213
cachableQuery.getAlias());
211214
}
212215

213-
private String applySortingIfNecessary(DeclaredQuery query, Sort sort) {
216+
/**
217+
* Query Sort Rewriter interface.
218+
*/
219+
interface QuerySortRewriter {
220+
String getSorted(DeclaredQuery query, Sort sort);
221+
}
222+
223+
/**
224+
* No-op query rewriter.
225+
*/
226+
enum NoOpQuerySortRewriter implements QuerySortRewriter {
227+
INSTANCE;
228+
229+
public String getSorted(DeclaredQuery query, Sort sort) {
230+
231+
if (sort.isSorted()) {
232+
throw new UnsupportedOperationException("NoOpQueryCache does not support sorting");
233+
}
214234

215-
if (sort.isUnsorted()) {
216235
return query.getQueryString();
217236
}
218-
return applySorting(query, sort);
237+
}
238+
239+
/**
240+
* Caching variant of {@link QuerySortRewriter}.
241+
*/
242+
class CachingQuerySortRewriter implements QuerySortRewriter {
243+
244+
private final ConcurrentLruCache<CachableQuery, String> queryCache = new ConcurrentLruCache<>(16,
245+
AbstractStringBasedJpaQuery.this::applySorting);
246+
247+
@Override
248+
public String getSorted(DeclaredQuery query, Sort sort) {
249+
250+
if (sort.isUnsorted()) {
251+
return query.getQueryString();
252+
}
253+
254+
return queryCache.get(new CachableQuery(query, sort));
255+
}
219256
}
220257

221258
/**
@@ -227,7 +264,7 @@ private String applySortingIfNecessary(DeclaredQuery query, Sort sort) {
227264
*/
228265
static class CachableQuery {
229266

230-
private DeclaredQuery declaredQuery;
267+
private final DeclaredQuery declaredQuery;
231268
private final String queryString;
232269
private final Sort sort;
233270

@@ -246,6 +283,7 @@ Sort getSort() {
246283
return sort;
247284
}
248285

286+
@Nullable
249287
String getAlias() {
250288
return declaredQuery.getAlias();
251289
}

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

+12-3
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,16 @@
3939
import java.lang.annotation.Annotation;
4040
import java.lang.reflect.AnnotatedElement;
4141
import java.lang.reflect.Member;
42-
import java.util.*;
42+
import java.util.ArrayList;
43+
import java.util.Collections;
44+
import java.util.HashMap;
45+
import java.util.HashSet;
46+
import java.util.Iterator;
47+
import java.util.List;
48+
import java.util.Locale;
49+
import java.util.Map;
50+
import java.util.Objects;
51+
import java.util.Set;
4352
import java.util.regex.Matcher;
4453
import java.util.regex.Pattern;
4554
import java.util.stream.Collectors;
@@ -568,7 +577,7 @@ public static <T> Query applyAndBind(String queryString, Iterable<T> entities, E
568577
*
569578
* @param originalQuery must not be {@literal null} or empty.
570579
* @return Guaranteed to be not {@literal null}.
571-
* @deprecated use {@link DeclaredQuery#deriveCountQuery(String, String)} instead.
580+
* @deprecated use {@link DeclaredQuery#deriveCountQuery(String)} instead.
572581
*/
573582
@Deprecated
574583
public static String createCountQueryFor(String originalQuery) {
@@ -582,7 +591,7 @@ public static String createCountQueryFor(String originalQuery) {
582591
* @param countProjection may be {@literal null}.
583592
* @return a query String to be used a count query for pagination. Guaranteed to be not {@literal null}.
584593
* @since 1.6
585-
* @deprecated use {@link DeclaredQuery#deriveCountQuery(String, String)} instead.
594+
* @deprecated use {@link DeclaredQuery#deriveCountQuery(String)} instead.
586595
*/
587596
@Deprecated
588597
public static String createCountQueryFor(String originalQuery, @Nullable String countProjection) {

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,11 @@
4949
import org.springframework.util.ReflectionUtils;
5050

5151
/**
52+
* Unit tests for {@link AbstractStringBasedJpaQuery}.
53+
*
5254
* @author Christoph Strobl
5355
*/
54-
public class AbstractStringBasedJpaQueryUnitTests {
56+
class AbstractStringBasedJpaQueryUnitTests {
5557

5658
@Test // GH-3310
5759
void shouldNotAttemptToAppendSortIfNoSortArgumentPresent() {

0 commit comments

Comments
 (0)