DATAREDIS-492 - Handle serializing arrays and collections.

Original Pull Request: #189
This commit is contained in:
Greg Turnquist
2016-04-11 16:20:54 -05:00
committed by Christoph Strobl
parent deec98efc6
commit 2492fbe332
3 changed files with 95 additions and 8 deletions

View File

@@ -16,6 +16,7 @@
package org.springframework.data.redis.core.convert;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
@@ -100,6 +101,7 @@ import org.springframework.util.comparator.NullSafeComparator;
* </pre>
*
* @author Christoph Strobl
* @author Greg Turnquist
* @since 1.7
*/
public class MappingRedisConverter implements RedisConverter, InitializingBean {
@@ -355,8 +357,8 @@ public class MappingRedisConverter implements RedisConverter, InitializingBean {
sink.setTimeToLive(ttl);
}
for (IndexedData indexeData : indexResolver.resolveIndexesFor(entity.getTypeInformation(), source)) {
sink.addIndexedData(indexeData);
for (IndexedData indexedData : indexResolver.resolveIndexesFor(entity.getTypeInformation(), source)) {
sink.addIndexedData(indexedData);
}
}
@@ -409,8 +411,22 @@ public class MappingRedisConverter implements RedisConverter, InitializingBean {
writeMap(keyspace, propertyStringPath, persistentProperty.getMapValueType(),
(Map<?, ?>) accessor.getProperty(persistentProperty), sink);
} else if (persistentProperty.isCollectionLike()) {
writeCollection(keyspace, propertyStringPath, (Collection<?>) accessor.getProperty(persistentProperty),
final Object property = accessor.getProperty(persistentProperty);
if (property == null || Iterable.class.isAssignableFrom(property.getClass())) {
writeCollection(keyspace, propertyStringPath, (Iterable<?>) property,
persistentProperty.getTypeInformation().getComponentType(), sink);
} else if (property.getClass().isArray()) {
writeCollection(keyspace, propertyStringPath, Arrays.asList((Object[]) property),
persistentProperty.getTypeInformation().getComponentType(), sink);
} else {
throw new RuntimeException("Don't know how to handle " + property.getClass() + " type collection");
}
} else if (persistentProperty.isEntity()) {
writeInternal(keyspace, propertyStringPath, accessor.getProperty(persistentProperty),
persistentProperty.getTypeInformation().getActualType(), sink);
@@ -482,7 +498,7 @@ public class MappingRedisConverter implements RedisConverter, InitializingBean {
* @param typeHint
* @param sink
*/
private void writeCollection(String keyspace, String path, Collection<?> values, TypeInformation<?> typeHint,
private void writeCollection(String keyspace, String path, Iterable<?> values, TypeInformation<?> typeHint,
RedisData sink) {
if (values == null) {
@@ -492,6 +508,10 @@ public class MappingRedisConverter implements RedisConverter, InitializingBean {
int i = 0;
for (Object value : values) {
if (value == null) {
break;
}
String currentPath = path + ".[" + i + "]";
if (customConversions.hasCustomWriteTarget(value.getClass())) {

View File

@@ -15,8 +15,10 @@
*/
package org.springframework.data.redis.core.convert;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
@@ -43,6 +45,7 @@ import org.springframework.util.Assert;
* {@link IndexConfiguration}.
*
* @author Christoph Strobl
* @author Greg Turnquist
* @since 1.7
*/
public class PathIndexResolver implements IndexResolver {
@@ -116,11 +119,23 @@ public class PathIndexResolver implements IndexResolver {
} else if (persistentProperty.isCollectionLike()) {
for (Object listValue : (Iterable<?>) propertyValue) {
final Iterable<?> iterable;
TypeInformation<?> typeToUse = updateTypeHintForActualValue(typeHint, listValue);
indexes.addAll(
if (Iterable.class.isAssignableFrom(propertyValue.getClass())) {
iterable = (Iterable) propertyValue;
} else if (propertyValue.getClass().isArray()) {
iterable = Arrays.asList((Object[]) propertyValue);
} else {
throw new RuntimeException("Don't know how to handle " + propertyValue.getClass() + " type of collection");
}
for (Object listValue : iterable) {
if (listValue != null) {
TypeInformation<?> typeToUse = updateTypeHintForActualValue(typeHint, listValue);
indexes.addAll(
doResolveIndexesFor(keyspace, currentPath, typeToUse.getActualType(), persistentProperty, listValue));
}
}
}

View File

@@ -43,6 +43,7 @@ import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@@ -75,6 +76,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
/**
* @author Christoph Strobl
* @author Greg Turnquist
*/
@RunWith(MockitoJUnitRunner.class)
public class MappingRedisConverterUnitTests {
@@ -146,7 +148,7 @@ public class MappingRedisConverterUnitTests {
* @see DATAREDIS-425
*/
@Test
public void writeDoesNotAppendPropertiesWithEmtpyCollections() {
public void writeDoesNotAppendPropertiesWithEmptyCollections() {
rand.firstname = "rand";
@@ -435,6 +437,27 @@ public class MappingRedisConverterUnitTests {
.containingUtf8String("physicalAttributes.[eye-color]", "grey"));
}
/**
* @see DATAREDIS-492
*/
@Test
public void writeHandlesArraysProperly() {
this.converter = new MappingRedisConverter(null, null, resolverMock);
this.converter
.setCustomConversions(new CustomConversions(Collections.singletonList(new ListToByteConverter())));
this.converter.afterPropertiesSet();
Map<String, Object> innerMap = new LinkedHashMap<String, Object>();
innerMap.put("address", "tyrionl@netflix.com");
innerMap.put("when", new String[]{"pipeline.failed"});
Map<String, Object> map = new LinkedHashMap<String, Object>();
map.put("email", Collections.singletonList(innerMap));
RedisData target = write(map);
}
/**
* @see DATAREDIS-425
*/
@@ -1375,6 +1398,35 @@ public class MappingRedisConverterUnitTests {
}
}
@WritingConverter
static class ListToByteConverter implements Converter<List, byte[]> {
private final ObjectMapper mapper;
private final Jackson2JsonRedisSerializer<List> serializer;
ListToByteConverter() {
mapper = new ObjectMapper();
mapper.setVisibility(mapper.getSerializationConfig().getDefaultVisibilityChecker()
.withFieldVisibility(Visibility.ANY).withGetterVisibility(Visibility.NONE)
.withSetterVisibility(Visibility.NONE).withCreatorVisibility(Visibility.NONE));
serializer = new Jackson2JsonRedisSerializer<List>(List.class);
serializer.setObjectMapper(mapper);
}
@Override
public byte[] convert(List source) {
if (source == null || source.isEmpty()) {
return null;
}
return serializer.serialize(source);
}
}
@ReadingConverter
static class MapToSpeciesConverter implements Converter<Map<String, byte[]>, Species> {