Skip to content

Commit 359c3e4

Browse files
christophstroblmp911de
authored andcommitted
DATAREDIS-503 - Add HashMapper implementation based on MappingRedisConverter.
We now support mapping of simple and complex types to Redis HASH structures applying the same structure as the Repository support. This allows Object to hash Mapping and its direct usage via RedisTemplate without the need of explicitly having to use the repository abstraction. Original pull request: #194.
1 parent f5ecd3a commit 359c3e4

File tree

3 files changed

+197
-0
lines changed

3 files changed

+197
-0
lines changed

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,14 @@ public void write(Object source, final RedisData sink) {
344344
if (!customConversions.hasCustomWriteTarget(source.getClass())) {
345345
typeMapper.writeType(ClassUtils.getUserClass(source), sink);
346346
}
347+
348+
if (entity == null) {
349+
350+
typeMapper.writeType(ClassUtils.getUserClass(source), sink);
351+
sink.getBucket().put("_raw", conversionService.convert(source, byte[].class));
352+
return;
353+
}
354+
347355
sink.setKeyspace(entity.getKeySpace());
348356

349357
writeInternal(entity.getKeySpace(), "", source, entity.getTypeInformation(), sink);
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
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.hash;
17+
18+
import java.io.Serializable;
19+
import java.util.Collections;
20+
import java.util.Map;
21+
import java.util.Set;
22+
23+
import org.springframework.data.redis.core.convert.CustomConversions;
24+
import org.springframework.data.redis.core.convert.IndexResolver;
25+
import org.springframework.data.redis.core.convert.IndexedData;
26+
import org.springframework.data.redis.core.convert.MappingRedisConverter;
27+
import org.springframework.data.redis.core.convert.RedisData;
28+
import org.springframework.data.redis.core.convert.ReferenceResolver;
29+
import org.springframework.data.redis.core.mapping.RedisMappingContext;
30+
import org.springframework.data.util.TypeInformation;
31+
32+
/**
33+
* {@link HashMapper} based on {@link MappingRedisConverter}. Does supports nested properties and simple types like
34+
* {@link String}.
35+
*
36+
* <pre>
37+
* <code>
38+
* class Person {
39+
*
40+
* String firstname;
41+
*
42+
* List&lt;String&gt; nicknames;
43+
* List&lt;Person&gt; coworkers;
44+
*
45+
* Address address;
46+
* }
47+
* </code>
48+
* </pre>
49+
*
50+
* The above is represented as:
51+
*
52+
* <pre>
53+
* <code>
54+
* _class=org.example.Person
55+
* firstname=rand
56+
* lastname=al'thor
57+
* coworkers.[0].firstname=mat
58+
* coworkers.[0].nicknames.[0]=prince of the ravens
59+
* coworkers.[1].firstname=perrin
60+
* coworkers.[1].address.city=two rivers
61+
* </code>
62+
* </pre>
63+
*
64+
* @author Christoph Strobl
65+
* @since 1.8
66+
*/
67+
public class ConvertingHashMapper implements HashMapper<Object, byte[], byte[]> {
68+
69+
private final MappingRedisConverter converter;
70+
71+
/**
72+
* Creates new {@link ConvertingHashMapper}.
73+
*/
74+
public ConvertingHashMapper() {
75+
this(new CustomConversions());
76+
}
77+
78+
/**
79+
* Creates new {@link ConvertingHashMapper}.
80+
*
81+
* @param customConversions can be {@literal null}.
82+
*/
83+
public ConvertingHashMapper(CustomConversions customConversions) {
84+
85+
MappingRedisConverter mappingConverter = new MappingRedisConverter(new RedisMappingContext(),
86+
new NoOpIndexResolver(), new NoOpReferenceResolver());
87+
mappingConverter.setCustomConversions(customConversions == null ? new CustomConversions() : customConversions);
88+
mappingConverter.afterPropertiesSet();
89+
90+
converter = mappingConverter;
91+
}
92+
93+
/*
94+
* (non-Javadoc)
95+
* @see org.springframework.data.redis.hash.HashMapper#toHash(java.lang.Object)
96+
*/
97+
@Override
98+
public Map<byte[], byte[]> toHash(Object source) {
99+
100+
if (source == null) {
101+
return Collections.emptyMap();
102+
}
103+
104+
RedisData sink = new RedisData();
105+
converter.write(source, sink);
106+
return sink.getBucket().rawMap();
107+
}
108+
109+
/*
110+
* (non-Javadoc)
111+
* @see org.springframework.data.redis.hash.HashMapper#fromHash(java.util.Map)
112+
*/
113+
@Override
114+
public Object fromHash(Map<byte[], byte[]> hash) {
115+
116+
if (hash == null || hash.isEmpty()) {
117+
return null;
118+
}
119+
120+
return converter.read(Object.class, new RedisData(hash));
121+
}
122+
123+
/**
124+
* {@link ReferenceResolver} implementation always returning an empty {@link Map}.
125+
*
126+
* @author Christoph Strobl
127+
*/
128+
private static class NoOpReferenceResolver implements ReferenceResolver {
129+
130+
private static final Map<byte[], byte[]> NO_REFERENCE = Collections.emptyMap();
131+
132+
@Override
133+
public Map<byte[], byte[]> resolveReference(Serializable id, String keyspace) {
134+
return NO_REFERENCE;
135+
}
136+
}
137+
138+
/**
139+
* {@link IndexResolver} always returning an empty {@link Set}.
140+
*
141+
* @author Christoph Strobl
142+
*/
143+
private static class NoOpIndexResolver implements IndexResolver {
144+
145+
private static final Set<IndexedData> NO_INDEXES = Collections.emptySet();
146+
147+
@Override
148+
public Set<IndexedData> resolveIndexesFor(TypeInformation<?> typeInformation, Object value) {
149+
return NO_INDEXES;
150+
}
151+
}
152+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
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.mapping;
17+
18+
import org.junit.Test;
19+
import org.springframework.data.redis.hash.ConvertingHashMapper;
20+
21+
/**
22+
* @author Christoph Strobl
23+
*/
24+
public class ConvertingHashMapperTests extends AbstractHashMapperTest {
25+
26+
protected ConvertingHashMapper mapperFor(Class t) {
27+
return new ConvertingHashMapper();
28+
}
29+
30+
/**
31+
* @see DATAREDIS-503
32+
*/
33+
@Test
34+
public void testSimpleType() {
35+
assertBackAndForwardMapping(new Integer(100));
36+
}
37+
}

0 commit comments

Comments
 (0)