Skip to content

Commit f3f4436

Browse files
Update collection handling in MappingRedisConverter.
When writing type hints for collection like sources use the interface type instead of the actual implementation and make sure to utilize Collection utils to create the target collection on read. See: #3179
1 parent 2a6bae6 commit f3f4436

File tree

3 files changed

+49
-13
lines changed

3 files changed

+49
-13
lines changed

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.Collection;
2121
import java.util.Collections;
2222
import java.util.Comparator;
23+
import java.util.EnumSet;
2324
import java.util.HashMap;
2425
import java.util.Iterator;
2526
import java.util.List;
@@ -178,7 +179,7 @@ public <R> R read(Class<R> type, RedisData source) {
178179
TypeInformation<?> readType = typeMapper.readType(source.getBucket().getPath(), TypeInformation.of(type));
179180

180181
return readType.isCollectionLike()
181-
? (R) readCollectionOrArray("", ArrayList.class, Object.class, source.getBucket())
182+
? (R) readCollectionOrArray("", readType.getType(), Object.class, source.getBucket())
182183
: doReadInternal("", type, source);
183184

184185
}
@@ -403,7 +404,14 @@ public void write(@Nullable Object source, RedisData sink) {
403404
}
404405

405406
if (source instanceof Collection collection) {
406-
typeMapper.writeType(ClassUtils.getUserClass(source), sink.getBucket().getPath());
407+
408+
Class<?> collectionTargetType = Collection.class;
409+
if (collection instanceof List) {
410+
collectionTargetType = List.class;
411+
} else if (collection instanceof Set) {
412+
collectionTargetType = collection instanceof EnumSet ? EnumSet.class : Set.class;
413+
}
414+
typeMapper.writeType(collectionTargetType, sink.getBucket().getPath());
407415
writeCollection(sink.getKeyspace(), "", collection, TypeInformation.of(Object.class), sink);
408416
return;
409417
}

src/main/java/org/springframework/data/redis/core/mapping/RedisMappingContext.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,14 @@ protected <T> RedisPersistentEntity<T> createPersistentEntity(TypeInformation<T>
9191
return new BasicRedisPersistentEntity<>(typeInformation, getKeySpaceResolver(), timeToLiveAccessor);
9292
}
9393

94+
@Override
95+
protected boolean shouldCreatePersistentEntityFor(TypeInformation<?> typeInformation) {
96+
if (typeInformation.isMap() || typeInformation.isCollectionLike()) {
97+
return false;
98+
}
99+
return super.shouldCreatePersistentEntityFor(typeInformation);
100+
}
101+
94102
@Override
95103
protected RedisPersistentProperty createPersistentProperty(Property property, RedisPersistentEntity<?> owner,
96104
SimpleTypeHolder simpleTypeHolder) {

src/test/java/org/springframework/data/redis/core/convert/MappingRedisConverterUnitTests.java

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -56,17 +56,24 @@
5656
import java.util.ArrayList;
5757
import java.util.Arrays;
5858
import java.util.Calendar;
59+
import java.util.Collection;
5960
import java.util.Collections;
6061
import java.util.Date;
6162
import java.util.HashMap;
6263
import java.util.LinkedHashMap;
6364
import java.util.List;
6465
import java.util.Map;
66+
import java.util.Set;
6567
import java.util.UUID;
68+
import java.util.stream.Stream;
6669

70+
import org.assertj.core.api.InstanceOfAssertFactories;
6771
import org.junit.jupiter.api.BeforeEach;
6872
import org.junit.jupiter.api.Test;
6973
import org.junit.jupiter.api.extension.ExtendWith;
74+
import org.junit.jupiter.params.ParameterizedTest;
75+
import org.junit.jupiter.params.provider.Arguments;
76+
import org.junit.jupiter.params.provider.MethodSource;
7077
import org.mockito.Mock;
7178
import org.mockito.junit.jupiter.MockitoExtension;
7279
import org.springframework.core.convert.converter.Converter;
@@ -1997,20 +2004,18 @@ void readGenericEntity() {
19972004

19982005
@Test // GH-2168, GH-3179
19992006
void writePlainList() {
2007+
20002008
List<Object> source = Arrays.asList("Hello", "stream", "message", 100L);
20012009
RedisTestData target = write(source);
2002-
Object classValue = target.getBucket().get("_class");
20032010

2004-
assertThat(classValue)
2005-
.as("_class metadata should be written")
2006-
.isNotNull()
2007-
.isInstanceOf(byte[].class);
2008-
assertThat(new String((byte[]) classValue, StandardCharsets.UTF_8))
2009-
.isEqualTo(ClassUtils.getUserClass(source).getName());
2010-
assertThat(target).containsEntry("[0]", "Hello")
2011-
.containsEntry("[1]", "stream")
2012-
.containsEntry("[2]", "message")
2013-
.containsEntry("[3]", "100");
2011+
assertThat(target) //
2012+
.containsEntry("_class", "java.util.List") //
2013+
.containsEntry("[0]", "Hello") //
2014+
.containsEntry("[0]._class", "java.lang.String") //
2015+
.containsEntry("[1]", "stream") //
2016+
.containsEntry("[2]", "message") //
2017+
.containsEntry("[3]", "100") //
2018+
.containsEntry("[3]._class", "java.lang.Long");
20142019
}
20152020

20162021
@Test // DATAREDIS-1175
@@ -2031,6 +2036,21 @@ void readPlainList() {
20312036
assertThat(target).containsExactly("Hello", "stream", "message", 100L);
20322037
}
20332038

2039+
@ParameterizedTest // GH-3179
2040+
@MethodSource("justCollections")
2041+
void readsPlainCollectionIfObjectTypeRequested(Class<?> type, Collection<Object> collection) {
2042+
2043+
RedisTestData source = write(collection);
2044+
2045+
Object target = this.converter.read(Object.class, source.getRedisData());
2046+
2047+
assertThat(target).isInstanceOf(type).asInstanceOf(InstanceOfAssertFactories.COLLECTION).containsExactlyElementsOf(collection);
2048+
}
2049+
2050+
private static Stream<Arguments> justCollections() {
2051+
return Stream.of(Arguments.of(List.class, Arrays.asList("Hello", "stream", "message", 100L)), Arguments.of(Set.class, Set.of("Hello", "stream", "message", 100L)));
2052+
}
2053+
20342054
private RedisTestData write(Object source) {
20352055

20362056
RedisData rdo = new RedisData();

0 commit comments

Comments
 (0)