Skip to content

Commit c07c37c

Browse files
DATAKV-112 - Make caching repository queries more explicit.
We introduced an explicit CachingKeyValuePartTreeQuery and allow setting the gernal repository query stategy via QueryCreatorType. By default queries will not be cached.
1 parent 91bb244 commit c07c37c

File tree

8 files changed

+202
-35
lines changed

8 files changed

+202
-35
lines changed

src/main/java/org/springframework/data/keyvalue/repository/config/KeyValueRepositoryConfigurationExtension.java

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2014 the original author or authors.
2+
* Copyright 2014-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -27,6 +27,7 @@
2727
import org.springframework.core.type.AnnotationMetadata;
2828
import org.springframework.data.keyvalue.core.mapping.context.KeyValueMappingContext;
2929
import org.springframework.data.keyvalue.repository.KeyValueRepository;
30+
import org.springframework.data.keyvalue.repository.query.KeyValuePartTreeQuery;
3031
import org.springframework.data.keyvalue.repository.query.SpelQueryCreator;
3132
import org.springframework.data.keyvalue.repository.support.KeyValueRepositoryFactoryBean;
3233
import org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource;
@@ -92,6 +93,7 @@ public void postProcess(BeanDefinitionBuilder builder, AnnotationRepositoryConfi
9293

9394
builder.addPropertyReference("keyValueOperations", attributes.getString(KEY_VALUE_TEMPLATE_BEAN_REF_ATTRIBUTE));
9495
builder.addPropertyValue("queryCreator", getQueryCreatorType(config));
96+
builder.addPropertyValue("queryType", getQueryType(config));
9597
builder.addPropertyReference("mappingContext", MAPPING_CONTEXT_BEAN_NAME);
9698
}
9799

@@ -106,16 +108,37 @@ private static Class<?> getQueryCreatorType(AnnotationRepositoryConfigurationSou
106108

107109
AnnotationMetadata metadata = config.getEnableAnnotationMetadata();
108110

109-
Map<String, Object> queryCreatorFoo = metadata.getAnnotationAttributes(QueryCreatorType.class.getName());
111+
Map<String, Object> queryCreatorAnnotationAttributes = metadata.getAnnotationAttributes(QueryCreatorType.class.getName());
110112

111-
if (queryCreatorFoo == null) {
113+
if (queryCreatorAnnotationAttributes == null) {
112114
return SpelQueryCreator.class;
113115
}
114116

115-
AnnotationAttributes queryCreatorAttributes = new AnnotationAttributes(queryCreatorFoo);
117+
AnnotationAttributes queryCreatorAttributes = new AnnotationAttributes(queryCreatorAnnotationAttributes);
116118
return queryCreatorAttributes.getClass("value");
117119
}
118120

121+
/**
122+
* Detects the query creator type to be used for the factory to set. Will lookup a {@link QueryCreatorType} annotation
123+
* on the {@code @Enable}-annotation or use {@link SpelQueryCreator} if not found.
124+
*
125+
* @param config
126+
* @return
127+
*/
128+
private static Class<?> getQueryType(AnnotationRepositoryConfigurationSource config) {
129+
130+
AnnotationMetadata metadata = config.getEnableAnnotationMetadata();
131+
132+
Map<String, Object> queryCreatorAnnotationAttributes = metadata.getAnnotationAttributes(QueryCreatorType.class.getName());
133+
134+
if (queryCreatorAnnotationAttributes == null) {
135+
return KeyValuePartTreeQuery.class;
136+
}
137+
138+
AnnotationAttributes queryCreatorAttributes = new AnnotationAttributes(queryCreatorAnnotationAttributes);
139+
return queryCreatorAttributes.getClass("repositoryQueryType");
140+
}
141+
119142
/*
120143
* (non-Javadoc)
121144
* @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#registerBeansForRoot(org.springframework.beans.factory.support.BeanDefinitionRegistry, org.springframework.data.repository.config.RepositoryConfigurationSource)

src/main/java/org/springframework/data/keyvalue/repository/config/QueryCreatorType.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2014 the original author or authors.
2+
* Copyright 2014-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -21,17 +21,28 @@
2121
import java.lang.annotation.RetentionPolicy;
2222
import java.lang.annotation.Target;
2323

24+
import org.springframework.data.keyvalue.repository.query.KeyValuePartTreeQuery;
25+
import org.springframework.data.repository.query.RepositoryQuery;
2426
import org.springframework.data.repository.query.parser.AbstractQueryCreator;
2527

2628
/**
2729
* Annotation to customize the query creator type to be used for a specific store.
2830
*
2931
* @author Oliver Gierke
32+
* @author Christoph Strobl
3033
*/
3134
@Documented
3235
@Retention(RetentionPolicy.RUNTIME)
3336
@Target(ElementType.ANNOTATION_TYPE)
3437
public @interface QueryCreatorType {
3538

3639
Class<? extends AbstractQueryCreator<?, ?>> value();
40+
41+
/**
42+
* The {@link RepositoryQuery} type to be created by the {@link QueryCreatorType#value()}.
43+
*
44+
* @return
45+
* @since 1.1
46+
*/
47+
Class<? extends RepositoryQuery> repositoryQueryType() default KeyValuePartTreeQuery.class;
3748
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Copyright 2016 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.keyvalue.repository.query;
17+
18+
import org.springframework.data.keyvalue.core.KeyValueOperations;
19+
import org.springframework.data.keyvalue.core.query.KeyValueQuery;
20+
import org.springframework.data.repository.query.EvaluationContextProvider;
21+
import org.springframework.data.repository.query.QueryMethod;
22+
import org.springframework.data.repository.query.parser.AbstractQueryCreator;
23+
import org.springframework.data.repository.query.parser.PartTree;
24+
25+
/**
26+
* {@link KeyValuePartTreeQuery} implementation deriving queries from {@link PartTree} using a predefined
27+
* {@link AbstractQueryCreator} that caches the once created query.
28+
*
29+
* @author Christoph Strobl
30+
* @since 1.1
31+
*/
32+
public class CachingKeyValuePartTreeQuery extends KeyValuePartTreeQuery {
33+
34+
private KeyValueQuery<?> cachedQuery;
35+
36+
public CachingKeyValuePartTreeQuery(QueryMethod queryMethod, EvaluationContextProvider evaluationContextProvider,
37+
KeyValueOperations keyValueOperations, Class<? extends AbstractQueryCreator<?, ?>> queryCreator) {
38+
super(queryMethod, evaluationContextProvider, keyValueOperations, queryCreator);
39+
}
40+
41+
/*
42+
* (non-Javadoc)
43+
* @see org.springframework.data.keyvalue.repository.query.KeyValuePartTreeQuery#prepareQuery(java.lang.Object[])
44+
*/
45+
protected KeyValueQuery<?> prepareQuery(Object[] parameters) {
46+
47+
if (cachedQuery == null) {
48+
cachedQuery = super.prepareQuery(parameters);
49+
}
50+
51+
return prepareQuery(cachedQuery, parameters);
52+
}
53+
}

src/main/java/org/springframework/data/keyvalue/repository/query/KeyValuePartTreeQuery.java

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,6 @@ public class KeyValuePartTreeQuery implements RepositoryQuery {
5252
private final KeyValueOperations keyValueOperations;
5353
private final Class<? extends AbstractQueryCreator<?, ?>> queryCreator;
5454

55-
private KeyValueQuery<?> query;
56-
5755
/**
5856
* Creates a new {@link KeyValuePartTreeQuery} for the given {@link QueryMethod}, {@link EvaluationContextProvider},
5957
* {@link KeyValueOperations} and query creator type.
@@ -77,15 +75,6 @@ public KeyValuePartTreeQuery(QueryMethod queryMethod, EvaluationContextProvider
7775
this.queryCreator = queryCreator;
7876
}
7977

80-
/*
81-
* (non-Javadoc)
82-
* @see org.springframework.data.repository.query.RepositoryQuery#getQueryMethod()
83-
*/
84-
@Override
85-
public QueryMethod getQueryMethod() {
86-
return queryMethod;
87-
}
88-
8978
/*
9079
* (non-Javadoc)
9180
* @see org.springframework.data.repository.query.RepositoryQuery#execute(java.lang.Object[])
@@ -133,31 +122,33 @@ protected Object doExecute(Object[] parameters, KeyValueQuery<?> query) {
133122
throw new UnsupportedOperationException("Query method not supported.");
134123
}
135124

136-
@SuppressWarnings({ "rawtypes", "unchecked" })
137125
protected KeyValueQuery<?> prepareQuery(Object[] parameters) {
138126

139-
ParametersParameterAccessor accessor = new ParametersParameterAccessor(getQueryMethod().getParameters(),
127+
return prepareQuery(createQuery(new ParametersParameterAccessor(getQueryMethod().getParameters(), parameters)),
140128
parameters);
129+
}
141130

142-
if (this.query == null) {
143-
this.query = createQuery(accessor);
144-
}
131+
@SuppressWarnings({ "rawtypes", "unchecked" })
132+
protected KeyValueQuery<?> prepareQuery(KeyValueQuery<?> instance, Object[] parameters) {
133+
134+
ParametersParameterAccessor accessor = new ParametersParameterAccessor(getQueryMethod().getParameters(),
135+
parameters);
145136

146-
KeyValueQuery<?> query = new KeyValueQuery(this.query.getCritieria());
137+
KeyValueQuery<?> query = new KeyValueQuery(instance.getCritieria());
147138

148-
if (this.query.getCritieria() instanceof SpelExpression) {
139+
if (instance.getCritieria() instanceof SpelExpression) {
149140

150141
EvaluationContext context = this.evaluationContextProvider.getEvaluationContext(getQueryMethod().getParameters(),
151142
parameters);
152-
query = new KeyValueQuery(new SpelCriteria((SpelExpression) this.query.getCritieria(), context));
143+
query = new KeyValueQuery(new SpelCriteria((SpelExpression) instance.getCritieria(), context));
153144
}
154145

155146
Pageable pageable = accessor.getPageable();
156147
Sort sort = accessor.getSort();
157148

158149
query.setOffset(pageable == null ? -1 : pageable.getOffset());
159150
query.setRows(pageable == null ? -1 : pageable.getPageSize());
160-
query.setSort(sort == null ? this.query.getSort() : sort);
151+
query.setSort(sort == null ? instance.getSort() : sort);
161152

162153
return query;
163154
}
@@ -170,4 +161,13 @@ public KeyValueQuery<?> createQuery(ParameterAccessor accessor) {
170161
.getConstructorIfAvailable(queryCreator, PartTree.class, ParameterAccessor.class);
171162
return (KeyValueQuery<?>) BeanUtils.instantiateClass(constructor, tree, accessor).createQuery();
172163
}
164+
165+
/*
166+
* (non-Javadoc)
167+
* @see org.springframework.data.repository.query.RepositoryQuery#getQueryMethod()
168+
*/
169+
@Override
170+
public QueryMethod getQueryMethod() {
171+
return queryMethod;
172+
}
173173
}

src/main/java/org/springframework/data/keyvalue/repository/support/KeyValueRepositoryFactory.java

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@
1818
import static org.springframework.data.querydsl.QueryDslUtils.*;
1919

2020
import java.io.Serializable;
21+
import java.lang.reflect.Constructor;
2122
import java.lang.reflect.Method;
2223

24+
import org.springframework.beans.BeanUtils;
2325
import org.springframework.data.keyvalue.core.KeyValueOperations;
2426
import org.springframework.data.keyvalue.repository.query.KeyValuePartTreeQuery;
2527
import org.springframework.data.keyvalue.repository.query.SpelQueryCreator;
@@ -40,6 +42,7 @@
4042
import org.springframework.data.repository.query.RepositoryQuery;
4143
import org.springframework.data.repository.query.parser.AbstractQueryCreator;
4244
import org.springframework.util.Assert;
45+
import org.springframework.util.ClassUtils;
4346

4447
/**
4548
* {@link RepositoryFactorySupport} specific of handing
@@ -55,6 +58,7 @@ public class KeyValueRepositoryFactory extends RepositoryFactorySupport {
5558
private final KeyValueOperations keyValueOperations;
5659
private final MappingContext<?, ?> context;
5760
private final Class<? extends AbstractQueryCreator<?, ?>> queryCreator;
61+
private final Class<? extends RepositoryQuery> repositoryQueryType;
5862

5963
/**
6064
* Creates a new {@link KeyValueRepositoryFactory} for the given {@link KeyValueOperations}.
@@ -75,12 +79,29 @@ public KeyValueRepositoryFactory(KeyValueOperations keyValueOperations) {
7579
public KeyValueRepositoryFactory(KeyValueOperations keyValueOperations,
7680
Class<? extends AbstractQueryCreator<?, ?>> queryCreator) {
7781

82+
this(keyValueOperations, queryCreator, KeyValuePartTreeQuery.class);
83+
}
84+
85+
/**
86+
* Creates a new {@link KeyValueRepositoryFactory} for the given {@link KeyValueOperations} and
87+
* {@link AbstractQueryCreator}-type.
88+
*
89+
* @param keyValueOperations must not be {@literal null}.
90+
* @param queryCreator must not be {@literal null}.
91+
* @param repositoryQueryType must not be {@literal null}.
92+
* @since 1.1
93+
*/
94+
public KeyValueRepositoryFactory(KeyValueOperations keyValueOperations,
95+
Class<? extends AbstractQueryCreator<?, ?>> queryCreator, Class<? extends RepositoryQuery> repositoryQueryType) {
96+
7897
Assert.notNull(keyValueOperations, "KeyValueOperations must not be null!");
7998
Assert.notNull(queryCreator, "Query creator type must not be null!");
99+
Assert.notNull(repositoryQueryType, "RepositoryQueryType type must not be null!");
80100

81101
this.queryCreator = queryCreator;
82102
this.keyValueOperations = keyValueOperations;
83103
this.context = keyValueOperations.getMappingContext();
104+
this.repositoryQueryType = repositoryQueryType;
84105
}
85106

86107
/*
@@ -134,7 +155,8 @@ private static boolean isQueryDslRepository(Class<?> repositoryInterface) {
134155
*/
135156
@Override
136157
protected QueryLookupStrategy getQueryLookupStrategy(Key key, EvaluationContextProvider evaluationContextProvider) {
137-
return new KeyValueQueryLookupStrategy(key, evaluationContextProvider, this.keyValueOperations, this.queryCreator);
158+
return new KeyValueQueryLookupStrategy(key, evaluationContextProvider, this.keyValueOperations, this.queryCreator,
159+
this.repositoryQueryType);
138160
}
139161

140162
/**
@@ -147,6 +169,7 @@ private static class KeyValueQueryLookupStrategy implements QueryLookupStrategy
147169
private KeyValueOperations keyValueOperations;
148170

149171
private Class<? extends AbstractQueryCreator<?, ?>> queryCreator;
172+
private Class<? extends RepositoryQuery> repositoryQueryType;
150173

151174
/**
152175
* Creates a new {@link KeyValueQueryLookupStrategy} for the given {@link Key}, {@link EvaluationContextProvider},
@@ -161,26 +184,47 @@ private static class KeyValueQueryLookupStrategy implements QueryLookupStrategy
161184
*/
162185
public KeyValueQueryLookupStrategy(Key key, EvaluationContextProvider evaluationContextProvider,
163186
KeyValueOperations keyValueOperations, Class<? extends AbstractQueryCreator<?, ?>> queryCreator) {
187+
this(key, evaluationContextProvider, keyValueOperations, queryCreator, KeyValuePartTreeQuery.class);
188+
}
189+
190+
/**
191+
* @param key
192+
* @param evaluationContextProvider
193+
* @param keyValueOperations
194+
* @param queryCreator
195+
* @since 1.1
196+
*/
197+
public KeyValueQueryLookupStrategy(Key key, EvaluationContextProvider evaluationContextProvider,
198+
KeyValueOperations keyValueOperations, Class<? extends AbstractQueryCreator<?, ?>> queryCreator,
199+
Class<? extends RepositoryQuery> repositoryQueryType) {
164200

165201
Assert.notNull(evaluationContextProvider, "EvaluationContextProvider must not be null!");
166202
Assert.notNull(keyValueOperations, "KeyValueOperations must not be null!");
167203
Assert.notNull(queryCreator, "Query creator type must not be null!");
204+
Assert.notNull(repositoryQueryType, "RepositoryQueryType type must not be null!");
168205

169206
this.evaluationContextProvider = evaluationContextProvider;
170207
this.keyValueOperations = keyValueOperations;
171208
this.queryCreator = queryCreator;
209+
this.repositoryQueryType = repositoryQueryType;
172210
}
173211

174212
/*
175213
* (non-Javadoc)
176214
* @see org.springframework.data.repository.query.QueryLookupStrategy#resolveQuery(java.lang.reflect.Method, org.springframework.data.repository.core.RepositoryMetadata, org.springframework.data.projection.ProjectionFactory, org.springframework.data.repository.core.NamedQueries)
177215
*/
178216
@Override
217+
@SuppressWarnings("unchecked")
179218
public RepositoryQuery resolveQuery(Method method, RepositoryMetadata metadata, ProjectionFactory factory,
180219
NamedQueries namedQueries) {
181220

182221
QueryMethod queryMethod = new QueryMethod(method, metadata, factory);
183-
return new KeyValuePartTreeQuery(queryMethod, evaluationContextProvider, this.keyValueOperations,
222+
223+
Constructor<? extends KeyValuePartTreeQuery> constructor = (Constructor<? extends KeyValuePartTreeQuery>) ClassUtils
224+
.getConstructorIfAvailable(this.repositoryQueryType, QueryMethod.class, EvaluationContextProvider.class,
225+
KeyValueOperations.class, Class.class);
226+
227+
return BeanUtils.instantiateClass(constructor, queryMethod, evaluationContextProvider, this.keyValueOperations,
184228
this.queryCreator);
185229
}
186230
}

0 commit comments

Comments
 (0)