diff --git a/src/main/java/org/springframework/data/redis/core/convert/MappingRedisConverter.java b/src/main/java/org/springframework/data/redis/core/convert/MappingRedisConverter.java index 21430984b..de32a69f3 100644 --- a/src/main/java/org/springframework/data/redis/core/convert/MappingRedisConverter.java +++ b/src/main/java/org/springframework/data/redis/core/convert/MappingRedisConverter.java @@ -15,6 +15,7 @@ */ package org.springframework.data.redis.core.convert; +import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -231,14 +232,39 @@ public class MappingRedisConverter implements RedisConverter, InitializingBean { else if (persistentProperty.isCollectionLike()) { if (conversionService.canConvert(byte[].class, persistentProperty.getComponentType())) { - accessor.setProperty(persistentProperty, - readCollectionOfSimpleTypes(currentPath, persistentProperty.getType(), - persistentProperty.getTypeInformation().getComponentType().getActualType().getType(), source)); + + Object targetValue = null; + if (persistentProperty.getType().isArray()) { + + List list = (List) readCollectionOfSimpleTypes(currentPath, ArrayList.class, + persistentProperty.getTypeInformation().getComponentType().getActualType().getType(), source); + + targetValue = list.toArray((Object[]) Array.newInstance( + persistentProperty.getTypeInformation().getComponentType().getActualType().getType(), list.size())); + } else { + targetValue = readCollectionOfSimpleTypes(currentPath, persistentProperty.getType(), + persistentProperty.getTypeInformation().getComponentType().getActualType().getType(), source); + } + + accessor.setProperty(persistentProperty, targetValue); } else { - accessor.setProperty(persistentProperty, - readCollectionOfComplexTypes(currentPath, persistentProperty.getType(), - persistentProperty.getTypeInformation().getComponentType().getActualType().getType(), - source.getBucket())); + + Object targetValue = null; + if (persistentProperty.getType().isArray()) { + + List list = (List) readCollectionOfComplexTypes(currentPath, ArrayList.class, + persistentProperty.getTypeInformation().getComponentType().getActualType().getType(), + source.getBucket()); + + targetValue = list.toArray((Object[]) Array.newInstance( + persistentProperty.getTypeInformation().getComponentType().getActualType().getType(), list.size())); + } else { + + targetValue = readCollectionOfComplexTypes(currentPath, persistentProperty.getType(), + persistentProperty.getTypeInformation().getComponentType().getActualType().getType(), + source.getBucket()); + } + accessor.setProperty(persistentProperty, targetValue); } } else if (persistentProperty.isEntity() && !conversionService.canConvert(byte[].class, @@ -417,11 +443,11 @@ public class MappingRedisConverter implements RedisConverter, InitializingBean { if (property == null || Iterable.class.isAssignableFrom(property.getClass())) { writeCollection(keyspace, propertyStringPath, (Iterable) property, - persistentProperty.getTypeInformation().getComponentType(), sink); + persistentProperty.getTypeInformation().getComponentType(), sink); } else if (property.getClass().isArray()) { writeCollection(keyspace, propertyStringPath, Arrays.asList((Object[]) property), - persistentProperty.getTypeInformation().getComponentType(), sink); + persistentProperty.getTypeInformation().getComponentType(), sink); } else { throw new RuntimeException("Don't know how to handle " + property.getClass() + " type collection"); diff --git a/src/test/java/org/springframework/data/redis/core/convert/ConversionTestEntities.java b/src/test/java/org/springframework/data/redis/core/convert/ConversionTestEntities.java index ccdf91c03..e75cfee33 100644 --- a/src/test/java/org/springframework/data/redis/core/convert/ConversionTestEntities.java +++ b/src/test/java/org/springframework/data/redis/core/convert/ConversionTestEntities.java @@ -160,4 +160,11 @@ public class ConversionTestEntities { int length; } + public static class WithArrays { + + Object[] arrayOfObject; + String[] arrayOfSimpleTypes; + Species[] arrayOfCompexTypes; + } + } diff --git a/src/test/java/org/springframework/data/redis/core/convert/MappingRedisConverterUnitTests.java b/src/test/java/org/springframework/data/redis/core/convert/MappingRedisConverterUnitTests.java index df88ffd35..1d3b5bfc1 100644 --- a/src/test/java/org/springframework/data/redis/core/convert/MappingRedisConverterUnitTests.java +++ b/src/test/java/org/springframework/data/redis/core/convert/MappingRedisConverterUnitTests.java @@ -47,6 +47,7 @@ import java.util.List; import java.util.Map; import java.util.UUID; +import org.hamcrest.core.IsEqual; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -66,6 +67,7 @@ import org.springframework.data.redis.core.convert.ConversionTestEntities.Person import org.springframework.data.redis.core.convert.ConversionTestEntities.Species; import org.springframework.data.redis.core.convert.ConversionTestEntities.TaVeren; import org.springframework.data.redis.core.convert.ConversionTestEntities.TheWheelOfTime; +import org.springframework.data.redis.core.convert.ConversionTestEntities.WithArrays; import org.springframework.data.redis.core.convert.KeyspaceConfiguration.KeyspaceSettings; import org.springframework.data.redis.core.mapping.RedisMappingContext; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; @@ -437,27 +439,6 @@ 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 innerMap = new LinkedHashMap(); - innerMap.put("address", "tyrionl@netflix.com"); - innerMap.put("when", new String[]{"pipeline.failed"}); - - Map map = new LinkedHashMap(); - map.put("email", Collections.singletonList(innerMap)); - - RedisData target = write(map); - } - /** * @see DATAREDIS-425 */ @@ -1348,6 +1329,104 @@ public class MappingRedisConverterUnitTests { assertThat(target.species.get(0).name, is("trolloc")); } + /** + * @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 innerMap = new LinkedHashMap(); + innerMap.put("address", "tyrionl@netflix.com"); + innerMap.put("when", new String[] { "pipeline.failed" }); + + Map map = new LinkedHashMap(); + map.put("email", Collections.singletonList(innerMap)); + + RedisData target = write(map); + } + + /** + * @see DATAREDIS-492 + */ + @Test + public void writeHandlesArraysOfSimpleTypeProperly() { + + WithArrays source = new WithArrays(); + source.arrayOfSimpleTypes = new String[] { "rand", "mat", "perrin" }; + + assertThat(write(source).getBucket(), + isBucket().containingUtf8String("arrayOfSimpleTypes.[0]", "rand") + .containingUtf8String("arrayOfSimpleTypes.[1]", "mat") + .containingUtf8String("arrayOfSimpleTypes.[2]", "perrin")); + } + + /** + * @see DATAREDIS-492 + */ + @Test + public void readHandlesArraysOfSimpleTypeProperly() { + + Map source = new LinkedHashMap(); + source.put("arrayOfSimpleTypes.[0]", "rand"); + source.put("arrayOfSimpleTypes.[1]", "mat"); + source.put("arrayOfSimpleTypes.[2]", "perrin"); + + WithArrays target = read(WithArrays.class, source); + + assertThat(target.arrayOfSimpleTypes, IsEqual.equalTo(new String[] { "rand", "mat", "perrin" })); + } + + /** + * @see DATAREDIS-492 + */ + @Test + public void writeHandlesArraysOfComplexTypeProperly() { + + WithArrays source = new WithArrays(); + + Species trolloc = new Species(); + trolloc.name = "trolloc"; + + Species myrddraal = new Species(); + myrddraal.name = "myrddraal"; + myrddraal.alsoKnownAs = Arrays.asList("halfmen", "fades", "neverborn"); + + source.arrayOfCompexTypes = new Species[] { trolloc, myrddraal }; + + assertThat(write(source).getBucket(), + isBucket().containingUtf8String("arrayOfCompexTypes.[0].name", "trolloc") // + .containingUtf8String("arrayOfCompexTypes.[1].name", "myrddraal") // + .containingUtf8String("arrayOfCompexTypes.[1].alsoKnownAs.[0]", "halfmen") // + .containingUtf8String("arrayOfCompexTypes.[1].alsoKnownAs.[1]", "fades") // + .containingUtf8String("arrayOfCompexTypes.[1].alsoKnownAs.[2]", "neverborn")); + } + + /** + * @see DATAREDIS-492 + */ + @Test + public void readHandlesArraysOfComplexTypeProperly() { + + Map source = new LinkedHashMap(); + source.put("arrayOfCompexTypes.[0].name", "trolloc"); + source.put("arrayOfCompexTypes.[1].name", "myrddraal"); + source.put("arrayOfCompexTypes.[1].alsoKnownAs.[0]", "halfmen"); + source.put("arrayOfCompexTypes.[1].alsoKnownAs.[1]", "fades"); + source.put("arrayOfCompexTypes.[1].alsoKnownAs.[2]", "neverborn"); + + WithArrays target = read(WithArrays.class, source); + + assertThat(target.arrayOfCompexTypes[0], notNullValue()); + assertThat(target.arrayOfCompexTypes[0].name, is("trolloc")); + assertThat(target.arrayOfCompexTypes[1], notNullValue()); + assertThat(target.arrayOfCompexTypes[1].name, is("myrddraal")); + assertThat(target.arrayOfCompexTypes[1].alsoKnownAs, contains("halfmen", "fades", "neverborn")); + } + private RedisData write(Object source) { RedisData rdo = new RedisData(); @@ -1355,6 +1434,10 @@ public class MappingRedisConverterUnitTests { return rdo; } + private T read(Class type, Map source) { + return converter.read(type, new RedisData(Bucket.newBucketFromStringMap(source))); + } + @WritingConverter static class AddressToBytesConverter implements Converter { @@ -1408,8 +1491,8 @@ public class MappingRedisConverterUnitTests { mapper = new ObjectMapper(); mapper.setVisibility(mapper.getSerializationConfig().getDefaultVisibilityChecker() - .withFieldVisibility(Visibility.ANY).withGetterVisibility(Visibility.NONE) - .withSetterVisibility(Visibility.NONE).withCreatorVisibility(Visibility.NONE)); + .withFieldVisibility(Visibility.ANY).withGetterVisibility(Visibility.NONE) + .withSetterVisibility(Visibility.NONE).withCreatorVisibility(Visibility.NONE)); serializer = new Jackson2JsonRedisSerializer(List.class); serializer.setObjectMapper(mapper); @@ -1426,7 +1509,6 @@ public class MappingRedisConverterUnitTests { } } - @ReadingConverter static class MapToSpeciesConverter implements Converter, Species> {