Skip to content

Commit 84351c0

Browse files
DATAREDIS-425 - Index definition and setup refactoring.
Remove IndexType and use dedicated classes for index definitions.
1 parent 6d4378f commit 84351c0

21 files changed

+814
-234
lines changed

src/main/java/org/springframework/data/redis/core/RedisKeyValueAdapter.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2015 the original author or authors.
2+
* Copyright 2015-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.
@@ -40,9 +40,9 @@
4040
import org.springframework.data.redis.connection.RedisConnection;
4141
import org.springframework.data.redis.connection.RedisConnectionFactory;
4242
import org.springframework.data.redis.core.convert.CustomConversions;
43-
import org.springframework.data.redis.core.convert.IndexResolverImpl;
4443
import org.springframework.data.redis.core.convert.KeyspaceConfiguration;
4544
import org.springframework.data.redis.core.convert.MappingRedisConverter;
45+
import org.springframework.data.redis.core.convert.PathIndexResolver;
4646
import org.springframework.data.redis.core.convert.RedisConverter;
4747
import org.springframework.data.redis.core.convert.RedisData;
4848
import org.springframework.data.redis.core.convert.ReferenceResolver;
@@ -131,8 +131,8 @@ public RedisKeyValueAdapter(RedisOperations<?, ?> redisOps, RedisMappingContext
131131
Assert.notNull(redisOps, "RedisOperations must not be null!");
132132
Assert.notNull(mappingContext, "RedisMappingContext must not be null!");
133133

134-
MappingRedisConverter mappingConverter = new MappingRedisConverter(mappingContext, new IndexResolverImpl(
135-
mappingContext), new ReferenceResolverImpl(this));
134+
MappingRedisConverter mappingConverter = new MappingRedisConverter(mappingContext,
135+
new PathIndexResolver(mappingContext), new ReferenceResolverImpl(this));
136136
mappingConverter.setCustomConversions(customConversions == null ? new CustomConversions() : customConversions);
137137
mappingConverter.afterPropertiesSet();
138138

src/main/java/org/springframework/data/redis/core/convert/MappingConfiguration.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2015 the original author or authors.
2+
* Copyright 2015-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.
@@ -15,7 +15,7 @@
1515
*/
1616
package org.springframework.data.redis.core.convert;
1717

18-
import org.springframework.data.redis.core.index.IndexConfiguration;
18+
import org.springframework.data.redis.core.index.ConfigurableIndexDefinitionProvider;
1919

2020
/**
2121
* {@link MappingConfiguration} is used for programmatic configuration of secondary indexes, key prefixes, expirations
@@ -26,7 +26,7 @@
2626
*/
2727
public class MappingConfiguration {
2828

29-
private final IndexConfiguration indexConfiguration;
29+
private final ConfigurableIndexDefinitionProvider indexConfiguration;
3030
private final KeyspaceConfiguration keyspaceConfiguration;
3131

3232
/**
@@ -35,7 +35,8 @@ public class MappingConfiguration {
3535
* @param indexConfiguration must not be {@literal null}.
3636
* @param keyspaceConfiguration must not be {@literal null}.
3737
*/
38-
public MappingConfiguration(IndexConfiguration indexConfiguration, KeyspaceConfiguration keyspaceConfiguration) {
38+
public MappingConfiguration(ConfigurableIndexDefinitionProvider indexConfiguration,
39+
KeyspaceConfiguration keyspaceConfiguration) {
3940

4041
this.indexConfiguration = indexConfiguration;
4142
this.keyspaceConfiguration = keyspaceConfiguration;
@@ -44,7 +45,7 @@ public MappingConfiguration(IndexConfiguration indexConfiguration, KeyspaceConfi
4445
/**
4546
* @return never {@literal null}.
4647
*/
47-
public IndexConfiguration getIndexConfiguration() {
48+
public ConfigurableIndexDefinitionProvider getIndexConfiguration() {
4849
return indexConfiguration;
4950
}
5051

src/main/java/org/springframework/data/redis/core/convert/MappingRedisConverter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2015 the original author or authors.
2+
* Copyright 2015-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.
@@ -138,7 +138,7 @@ public MappingRedisConverter(RedisMappingContext mappingContext, IndexResolver i
138138

139139
this.referenceResolver = referenceResolver;
140140

141-
this.indexResolver = indexResolver != null ? indexResolver : new IndexResolverImpl(this.mappingContext);
141+
this.indexResolver = indexResolver != null ? indexResolver : new PathIndexResolver(this.mappingContext);
142142
}
143143

144144
/*

src/main/java/org/springframework/data/redis/core/convert/IndexResolverImpl.java renamed to src/main/java/org/springframework/data/redis/core/convert/PathIndexResolver.java

Lines changed: 39 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,13 @@
2525
import org.springframework.data.mapping.PersistentProperty;
2626
import org.springframework.data.mapping.PersistentPropertyAccessor;
2727
import org.springframework.data.mapping.PropertyHandler;
28+
import org.springframework.data.redis.core.index.ConfigurableIndexDefinitionProvider;
2829
import org.springframework.data.redis.core.index.IndexConfiguration;
29-
import org.springframework.data.redis.core.index.IndexConfiguration.RedisIndexSetting;
30+
import org.springframework.data.redis.core.index.IndexDefinition;
31+
import org.springframework.data.redis.core.index.IndexDefinition.Condition;
32+
import org.springframework.data.redis.core.index.IndexDefinition.IndexingContext;
3033
import org.springframework.data.redis.core.index.Indexed;
34+
import org.springframework.data.redis.core.index.SimpleIndexDefinition;
3135
import org.springframework.data.redis.core.mapping.RedisMappingContext;
3236
import org.springframework.data.redis.core.mapping.RedisPersistentEntity;
3337
import org.springframework.data.util.ClassTypeInformation;
@@ -41,24 +45,24 @@
4145
* @author Christoph Strobl
4246
* @since 1.7
4347
*/
44-
public class IndexResolverImpl implements IndexResolver {
48+
public class PathIndexResolver implements IndexResolver {
4549

46-
private IndexConfiguration indexConfiguration;
50+
private ConfigurableIndexDefinitionProvider indexConfiguration;
4751
private RedisMappingContext mappingContext;
4852

4953
/**
50-
* Creates new {@link IndexResolverImpl} with empty {@link IndexConfiguration}.
54+
* Creates new {@link PathIndexResolver} with empty {@link IndexConfiguration}.
5155
*/
52-
public IndexResolverImpl() {
56+
public PathIndexResolver() {
5357
this(new RedisMappingContext());
5458
}
5559

5660
/**
57-
* Creates new {@link IndexResolverImpl} with given {@link IndexConfiguration}.
61+
* Creates new {@link PathIndexResolver} with given {@link IndexConfiguration}.
5862
*
5963
* @param mapppingContext must not be {@literal null}.
6064
*/
61-
public IndexResolverImpl(RedisMappingContext mappingContext) {
65+
public PathIndexResolver(RedisMappingContext mappingContext) {
6266

6367
Assert.notNull(mappingContext, "MappingContext must not be null!");
6468
this.mappingContext = mappingContext;
@@ -160,28 +164,43 @@ protected Set<IndexedData> resolveIndex(String keyspace, String propertyPath, Pe
160164
Set<IndexedData> data = new LinkedHashSet<IndexedData>();
161165

162166
if (indexConfiguration.hasIndexFor(keyspace, path)) {
163-
for (RedisIndexSetting indexSetting : indexConfiguration.getIndexDefinitionsFor(keyspace, path)) {
164-
data.add(new SimpleIndexedPropertyValue(keyspace, indexSetting.getIndexName(), value));
165-
}
166167

168+
IndexingContext context = new IndexingContext(keyspace, path, property != null ? property.getTypeInformation()
169+
: ClassTypeInformation.OBJECT);
170+
171+
for (IndexDefinition indexDefinition : indexConfiguration.getIndexDefinitionsFor(keyspace, path)) {
172+
173+
if (!verifyConditions(indexDefinition.getConditions(), value, context)) {
174+
continue;
175+
}
176+
177+
data.add(new SimpleIndexedPropertyValue(keyspace, indexDefinition.getIndexName(), indexDefinition
178+
.valueTransformer().convert(value)));
179+
}
167180
}
168181

169182
else if (property != null && property.isAnnotationPresent(Indexed.class)) {
170183

171-
Indexed indexed = property.findAnnotation(Indexed.class);
184+
SimpleIndexDefinition indexDefinition = new SimpleIndexDefinition(keyspace, path);
185+
indexConfiguration.addIndexDefinition(indexDefinition);
172186

173-
indexConfiguration.addIndexDefinition(new RedisIndexSetting(keyspace, path, indexed.type()));
187+
data.add(new SimpleIndexedPropertyValue(keyspace, path, indexDefinition.valueTransformer().convert(value)));
188+
}
189+
return data;
190+
}
191+
192+
@SuppressWarnings({ "rawtypes", "unchecked" })
193+
private boolean verifyConditions(Iterable<Condition<?>> conditions, Object value, IndexingContext context) {
174194

175-
switch (indexed.type()) {
176-
case SIMPLE:
177-
data.add(new SimpleIndexedPropertyValue(keyspace, path, value));
178-
break;
179-
default:
180-
throw new IllegalArgumentException(String.format("Unsupported index type '%s' for path '%s'.",
181-
indexed.type(), path));
195+
for (Condition condition : conditions) {
196+
197+
// TODO: generics lookup
198+
if (!condition.matches(value, context)) {
199+
return false;
182200
}
183201
}
184-
return data;
202+
203+
return true;
185204
}
186205

187206
private String normalizeIndexPath(String path, PersistentProperty<?> property) {

src/main/java/org/springframework/data/redis/core/convert/SpelIndexResolver.java

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,16 @@
1616
package org.springframework.data.redis.core.convert;
1717

1818
import java.util.Collections;
19+
import java.util.HashMap;
1920
import java.util.HashSet;
21+
import java.util.Map;
2022
import java.util.Set;
2123

2224
import org.springframework.context.expression.BeanFactoryResolver;
2325
import org.springframework.data.keyvalue.core.mapping.KeyValuePersistentEntity;
24-
import org.springframework.data.redis.core.index.IndexConfiguration;
25-
import org.springframework.data.redis.core.index.IndexConfiguration.RedisIndexSetting;
26+
import org.springframework.data.redis.core.index.ConfigurableIndexDefinitionProvider;
27+
import org.springframework.data.redis.core.index.IndexDefinition;
28+
import org.springframework.data.redis.core.index.SpelIndexDefinition;
2629
import org.springframework.data.redis.core.mapping.RedisMappingContext;
2730
import org.springframework.data.util.TypeInformation;
2831
import org.springframework.expression.BeanResolver;
@@ -35,16 +38,19 @@
3538
* An {@link IndexResolver} that resolves {@link IndexedData} using a {@link SpelExpressionParser}.
3639
*
3740
* @author Rob Winch
41+
* @author Christoph Strobl
3842
* @since 1.7
3943
*/
4044
public class SpelIndexResolver implements IndexResolver {
4145

42-
private final IndexConfiguration settings;
46+
private final ConfigurableIndexDefinitionProvider settings;
4347
private final SpelExpressionParser parser;
4448
private final RedisMappingContext mappingContext;
4549

4650
private BeanResolver beanResolver;
4751

52+
private Map<SpelIndexDefinition, Expression> expressionCache;
53+
4854
/**
4955
* Creates a new instance using a default {@link SpelExpressionParser}.
5056
*
@@ -66,6 +72,7 @@ public SpelIndexResolver(RedisMappingContext mappingContext, SpelExpressionParse
6672
Assert.notNull(parser, "SpelExpressionParser must not be null!");
6773
this.mappingContext = mappingContext;
6874
this.settings = mappingContext.getMappingConfiguration().getIndexConfiguration();
75+
this.expressionCache = new HashMap<SpelIndexDefinition, Expression>();
6976
this.parser = parser;
7077
}
7178

@@ -88,26 +95,41 @@ public Set<IndexedData> resolveIndexesFor(TypeInformation<?> typeInformation, Ob
8895

8996
Set<IndexedData> indexes = new HashSet<IndexedData>();
9097

91-
for (RedisIndexSetting setting : settings.getIndexDefinitionsFor(keyspace)) {
98+
for (IndexDefinition setting : settings.getIndexDefinitionsFor(keyspace)) {
9299

93-
Expression expression = parser.parseExpression(setting.getPath());
94-
StandardEvaluationContext context = new StandardEvaluationContext();
95-
context.setRootObject(value);
96-
context.setVariable("this", value);
100+
if (setting instanceof SpelIndexDefinition) {
97101

98-
if (beanResolver != null) {
99-
context.setBeanResolver(beanResolver);
100-
}
102+
Expression expression = getAndCacheIfAbsent((SpelIndexDefinition) setting);
103+
104+
StandardEvaluationContext context = new StandardEvaluationContext();
105+
context.setRootObject(value);
106+
context.setVariable("this", value);
101107

102-
Object index = expression.getValue(context);
103-
if (index != null) {
104-
indexes.add(new SimpleIndexedPropertyValue(keyspace, setting.getIndexName(), index));
108+
if (beanResolver != null) {
109+
context.setBeanResolver(beanResolver);
110+
}
111+
112+
Object index = expression.getValue(context);
113+
if (index != null) {
114+
indexes.add(new SimpleIndexedPropertyValue(keyspace, setting.getIndexName(), index));
115+
}
105116
}
106117
}
107118

108119
return indexes;
109120
}
110121

122+
private Expression getAndCacheIfAbsent(SpelIndexDefinition indexDefinition) {
123+
124+
if (expressionCache.containsKey(indexDefinition)) {
125+
return expressionCache.get(indexDefinition);
126+
}
127+
128+
Expression expression = parser.parseExpression(indexDefinition.getExpression());
129+
expressionCache.put(indexDefinition, expression);
130+
return expression;
131+
}
132+
111133
/**
112134
* Allows setting the BeanResolver
113135
*
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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.redis.core.index;
17+
18+
/**
19+
* {@link IndexDefinitionProvider} that allows registering new {@link IndexDefinition} via
20+
* {@link IndexDefinitionRegistry}.
21+
*
22+
* @author Christoph Strobl
23+
* @since 1.7
24+
*/
25+
public interface ConfigurableIndexDefinitionProvider extends IndexDefinitionProvider, IndexDefinitionRegistry {
26+
27+
}

0 commit comments

Comments
 (0)