Skip to content

Commit 5e3e449

Browse files
DATAREDIS-425 - Additional mapping options.
- Allow Converters to read/write Map<String,byte[]> for more influence on actual mapping. - Use provided type passed down from template to not require to have an explicit _class field on root level. This one requires DATAKV-117
1 parent 81b436f commit 5e3e449

File tree

6 files changed

+709
-43
lines changed

6 files changed

+709
-43
lines changed

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

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import org.springframework.data.redis.connection.Message;
3939
import org.springframework.data.redis.connection.RedisConnection;
4040
import org.springframework.data.redis.connection.RedisConnectionFactory;
41+
import org.springframework.data.redis.core.convert.CustomConversions;
4142
import org.springframework.data.redis.core.convert.IndexResolverImpl;
4243
import org.springframework.data.redis.core.convert.MappingRedisConverter;
4344
import org.springframework.data.redis.core.convert.RedisConverter;
@@ -65,18 +66,44 @@ public class RedisKeyValueAdapter extends AbstractKeyValueAdapter implements App
6566
private RedisMessageListenerContainer messageListenerContainer;
6667
private KeyExpirationEventMessageListener expirationListener;
6768

69+
/**
70+
* Creates new {@link RedisKeyValueAdapter} with default {@link RedisMappingContext} and default
71+
* {@link CustomConversions}.
72+
*
73+
* @param redisOps must not be {@literal null}.
74+
*/
6875
public RedisKeyValueAdapter(RedisOperations<?, ?> redisOps) {
6976
this(redisOps, new RedisMappingContext());
7077
}
7178

79+
/**
80+
* Creates new {@link RedisKeyValueAdapter} with default {@link CustomConversions}.
81+
*
82+
* @param redisOps must not be {@literal null}.
83+
* @param mappingContext must not be {@literal null}.
84+
*/
7285
public RedisKeyValueAdapter(RedisOperations<?, ?> redisOps, RedisMappingContext mappingContext) {
86+
this(redisOps, mappingContext, new CustomConversions());
87+
}
88+
89+
/**
90+
* Creates new {@link RedisKeyValueAdapter}.
91+
*
92+
* @param redisOps must not be {@literal null}.
93+
* @param mappingContext must not be {@literal null}.
94+
* @param customConversions can be {@literal null}.
95+
*/
96+
public RedisKeyValueAdapter(RedisOperations<?, ?> redisOps, RedisMappingContext mappingContext,
97+
CustomConversions customConversions) {
7398

7499
super(new RedisQueryEngine());
75100

76101
Assert.notNull(redisOps, "RedisOperations must not be null!");
102+
Assert.notNull(mappingContext, "RedisMappingContext must not be null!");
77103

78104
MappingRedisConverter mappingConverter = new MappingRedisConverter(mappingContext, new IndexResolverImpl(
79105
mappingContext.getMappingConfiguration().getIndexConfiguration()), new ReferenceResolverImpl(this));
106+
mappingConverter.setCustomConversions(customConversions == null ? new CustomConversions() : customConversions);
80107
mappingConverter.afterPropertiesSet();
81108

82109
converter = mappingConverter;
@@ -179,6 +206,16 @@ public Boolean doInRedis(RedisConnection connection) throws DataAccessException
179206
* @see org.springframework.data.keyvalue.core.KeyValueAdapter#get(java.io.Serializable, java.io.Serializable)
180207
*/
181208
public Object get(Serializable id, Serializable keyspace) {
209+
return get(id, keyspace, Object.class);
210+
}
211+
212+
/**
213+
* @param id
214+
* @param keyspace
215+
* @param type
216+
* @return
217+
*/
218+
public <T> T get(Serializable id, Serializable keyspace, Class<T> type) {
182219

183220
final byte[] binId = createKey(keyspace, id);
184221

@@ -190,19 +227,31 @@ public Map<byte[], byte[]> doInRedis(RedisConnection connection) throws DataAcce
190227
}
191228
});
192229

193-
return converter.read(Object.class, new RedisData(raw));
230+
RedisData data = new RedisData(raw);
231+
data.setId(id);
232+
data.setKeyspace(keyspace.toString());
233+
234+
return converter.read(type, data);
194235
}
195236

196237
/*
197238
* (non-Javadoc)
198239
* @see org.springframework.data.keyvalue.core.KeyValueAdapter#delete(java.io.Serializable, java.io.Serializable)
199240
*/
200241
public Object delete(final Serializable id, final Serializable keyspace) {
242+
return delete(id, keyspace, Object.class);
243+
}
244+
245+
/*
246+
* (non-Javadoc)
247+
* @see org.springframework.data.keyvalue.core.AbstractKeyValueAdapter#delete(java.io.Serializable, java.io.Serializable, java.lang.Class)
248+
*/
249+
public <T> T delete(final Serializable id, final Serializable keyspace, final Class<T> type) {
201250

202251
final byte[] binId = toBytes(id);
203252
final byte[] binKeyspace = toBytes(keyspace);
204253

205-
Object o = get(id, keyspace);
254+
T o = get(id, keyspace, type);
206255

207256
if (o != null) {
208257

@@ -472,6 +521,11 @@ private boolean isKeyExpirationMessage(Message message) {
472521
}
473522
}
474523

524+
/**
525+
* {@link ReferenceResolver} using {@link RedisKeyValueAdapter} to read and convert referenced entities.
526+
*
527+
* @author Christoph Strobl
528+
*/
475529
static class ReferenceResolverImpl implements ReferenceResolver {
476530

477531
private RedisKeyValueAdapter adapter;
@@ -487,6 +541,9 @@ public ReferenceResolverImpl(RedisKeyValueAdapter adapter) {
487541
this.adapter = adapter;
488542
}
489543

544+
/**
545+
* @param adapter
546+
*/
490547
public void setAdapter(RedisKeyValueAdapter adapter) {
491548
this.adapter = adapter;
492549
}
@@ -497,7 +554,7 @@ public void setAdapter(RedisKeyValueAdapter adapter) {
497554
*/
498555
@Override
499556
public <T> T resolveReference(Serializable id, Serializable keyspace, Class<T> type) {
500-
return (T) adapter.get(id, keyspace);
557+
return (T) adapter.get(id, keyspace, type);
501558
}
502559
}
503560

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

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.Arrays;
2121
import java.util.Collection;
2222
import java.util.Comparator;
23+
import java.util.LinkedHashMap;
2324
import java.util.List;
2425
import java.util.Map;
2526
import java.util.Set;
@@ -49,14 +50,13 @@ public RedisQueryEngine(CriteriaAccessor<RedisOperationChain> criteriaAccessor,
4950
super(criteriaAccessor, sortAccessor);
5051
}
5152

52-
@Override
53-
public Collection<?> execute(final RedisOperationChain criteria, Comparator<?> sort, int offset, int rows,
54-
final Serializable keyspace) {
53+
public <T> Collection<T> execute(final RedisOperationChain criteria, final Comparator<?> sort, int offset, int rows,
54+
final Serializable keyspace, Class<T> type) {
5555

56-
RedisCallback<List<Map<byte[], byte[]>>> callback = new RedisCallback<List<Map<byte[], byte[]>>>() {
56+
RedisCallback<Map<byte[], Map<byte[], byte[]>>> callback = new RedisCallback<Map<byte[], Map<byte[], byte[]>>>() {
5757

5858
@Override
59-
public List<Map<byte[], byte[]>> doInRedis(RedisConnection connection) throws DataAccessException {
59+
public Map<byte[], Map<byte[], byte[]>> doInRedis(RedisConnection connection) throws DataAccessException {
6060

6161
String key = keyspace + ":";
6262
byte[][] keys = new byte[criteria.getSismember().size()][];
@@ -70,33 +70,45 @@ public List<Map<byte[], byte[]>> doInRedis(RedisConnection connection) throws Da
7070

7171
byte[] keyspaceBin = getAdapter().getConverter().getConversionService().convert(keyspace + ":", byte[].class);
7272

73-
final List<Map<byte[], byte[]>> rawData = new ArrayList<Map<byte[], byte[]>>();
73+
final Map<byte[], Map<byte[], byte[]>> rawData = new LinkedHashMap<byte[], Map<byte[], byte[]>>();
7474

7575
for (byte[] id : allKeys) {
7676

7777
byte[] singleKey = Arrays.copyOf(keyspaceBin, id.length + keyspaceBin.length);
7878
System.arraycopy(id, 0, singleKey, keyspaceBin.length, id.length);
7979

80-
rawData.add(connection.hGetAll(singleKey));
80+
rawData.put(id, connection.hGetAll(singleKey));
8181
}
8282

8383
return rawData;
8484

8585
}
8686
};
8787

88-
List<Map<byte[], byte[]>> raw = this.getAdapter().execute(callback);
88+
Map<byte[], Map<byte[], byte[]>> raw = this.getAdapter().execute(callback);
89+
90+
List<T> result = new ArrayList<T>(raw.size());
91+
for (Map.Entry<byte[], Map<byte[], byte[]>> entry : raw.entrySet()) {
92+
93+
RedisData data = new RedisData(entry.getValue());
94+
data.setId(getAdapter().getConverter().getConversionService().convert(entry.getKey(), String.class));
95+
data.setKeyspace(keyspace.toString());
96+
97+
T converted = this.getAdapter().getConverter().read(type, data);
8998

90-
List<Object> result = new ArrayList<Object>(raw.size());
91-
for (Map<byte[], byte[]> rawData : raw) {
92-
Object converted = this.getAdapter().getConverter().read(Object.class, new RedisData(rawData));
9399
if (converted != null) {
94100
result.add(converted);
95101
}
96102
}
97103
return result;
98104
}
99105

106+
@Override
107+
public Collection<?> execute(final RedisOperationChain criteria, Comparator<?> sort, int offset, int rows,
108+
final Serializable keyspace) {
109+
return execute(criteria, sort, offset, rows, keyspace, Object.class);
110+
}
111+
100112
@Override
101113
public long count(final RedisOperationChain criteria, final Serializable keyspace) {
102114

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import java.nio.charset.Charset;
1919
import java.util.Collection;
20+
import java.util.Collections;
2021
import java.util.LinkedHashMap;
2122
import java.util.LinkedHashSet;
2223
import java.util.Map;
@@ -78,6 +79,11 @@ public byte[] get(String path) {
7879
return data.get(path);
7980
}
8081

82+
/**
83+
* A set view of the mappings contained in this bucket.
84+
*
85+
* @return never {@literal null}.
86+
*/
8187
public Set<Entry<String, byte[]>> entrySet() {
8288
return data.entrySet();
8389
}
@@ -89,14 +95,29 @@ public boolean isEmpty() {
8995
return data.isEmpty();
9096
}
9197

98+
/**
99+
* @return never {@literal null}.
100+
*/
92101
public Collection<byte[]> values() {
93102
return data.values();
94103
}
95104

105+
/**
106+
* @return never {@literal null}.
107+
*/
96108
public Set<String> keySet() {
97109
return data.keySet();
98110
}
99111

112+
/**
113+
* Key/value pairs contained in the {@link Bucket}.
114+
*
115+
* @return never {@literal null}.
116+
*/
117+
public Map<String, byte[]> asMap() {
118+
return Collections.unmodifiableMap(this.data);
119+
}
120+
100121
public Bucket extract(String prefix) {
101122

102123
Bucket partial = new Bucket();

0 commit comments

Comments
 (0)