Skip to content

Commit 551b27d

Browse files
christophstroblmp911de
authored andcommitted
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. Original pull request: #18.
1 parent b40c8c1 commit 551b27d

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)