Skip to content

Commit f353a09

Browse files
committed
Consider type hints of the actual value in MappingRedisConverter.
We now consider the actual value type when determining whether a value should be considered an entity. Previously, we relied on PersistentProperty type information only which made it impossible to use generic-typed (or Object) properties for entities. Closes #2349
1 parent c0821be commit f353a09

File tree

2 files changed

+63
-16
lines changed

2 files changed

+63
-16
lines changed

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

+20-16
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
import org.springframework.data.redis.core.mapping.RedisPersistentProperty;
5757
import org.springframework.data.redis.util.ByteUtils;
5858
import org.springframework.data.util.ClassTypeInformation;
59+
import org.springframework.data.util.ProxyUtils;
5960
import org.springframework.data.util.TypeInformation;
6061
import org.springframework.lang.Nullable;
6162
import org.springframework.util.Assert;
@@ -258,12 +259,20 @@ private <R> R doReadInternal(String path, Class<R> type, RedisData source) {
258259
protected Object readProperty(String path, RedisData source, RedisPersistentProperty persistentProperty) {
259260

260261
String currentPath = !path.isEmpty() ? path + "." + persistentProperty.getName() : persistentProperty.getName();
262+
TypeInformation<?> typeInformation = typeMapper.readType(source.getBucket().getPropertyPath(currentPath),
263+
persistentProperty.getTypeInformation());
261264

262-
TypeInformation<?> typeInformation = persistentProperty.getTypeInformation();
265+
if (typeInformation.isMap()) {
263266

264-
if (persistentProperty.isMap()) {
267+
Class<?> mapValueType = null;
265268

266-
Class<?> mapValueType = persistentProperty.getMapValueType();
269+
if (typeInformation.getMapValueType() != null) {
270+
mapValueType = typeInformation.getMapValueType().getType();
271+
}
272+
273+
if (mapValueType == null && persistentProperty.isMap()) {
274+
mapValueType = persistentProperty.getMapValueType();
275+
}
267276

268277
if (mapValueType == null) {
269278
throw new IllegalArgumentException("Unable to retrieve MapValueType");
@@ -293,16 +302,14 @@ protected Object readProperty(String path, RedisData source, RedisPersistentProp
293302
}
294303
}
295304

296-
if (persistentProperty.isEntity()
305+
if (mappingContext.getPersistentEntity(typeInformation) != null
297306
&& !conversionService.canConvert(byte[].class, typeInformation.getRequiredActualType().getType())) {
298307

299308
Bucket bucket = source.getBucket().extract(currentPath + ".");
300309

301310
RedisData newBucket = new RedisData(bucket);
302-
TypeInformation<?> typeToRead = typeMapper.readType(bucket.getPropertyPath(currentPath),
303-
typeInformation);
304311

305-
return readInternal(currentPath, typeToRead.getType(), newBucket);
312+
return readInternal(currentPath, typeInformation.getType(), newBucket);
306313
}
307314

308315
byte[] sourceBytes = source.getBucket().get(currentPath);
@@ -580,8 +587,7 @@ RedisPersistentProperty getTargetPropertyOrNullForPath(String path, Class<?> typ
580587
* @param sink
581588
*/
582589
private void writeInternal(@Nullable String keyspace, String path, @Nullable Object value,
583-
TypeInformation<?> typeHint,
584-
RedisData sink) {
590+
TypeInformation<?> typeHint, RedisData sink) {
585591

586592
if (value == null) {
587593
return;
@@ -656,16 +662,14 @@ private void writeInternal(@Nullable String keyspace, String path, @Nullable Obj
656662
}
657663
}
658664

659-
} else if (persistentProperty.isEntity()) {
665+
} else if (propertyValue != null) {
660666

661-
if (propertyValue != null) {
662-
writeInternal(keyspace, propertyStringPath, propertyValue,
663-
persistentProperty.getTypeInformation().getRequiredActualType(), sink);
664-
}
665-
} else {
667+
if (customConversions.isSimpleType(ProxyUtils.getUserClass(propertyValue.getClass()))) {
666668

667-
if (propertyValue != null) {
668669
writeToBucket(propertyStringPath, propertyValue, sink, persistentProperty.getType());
670+
} else {
671+
writeInternal(keyspace, propertyStringPath, propertyValue,
672+
persistentProperty.getTypeInformation().getRequiredActualType(), sink);
669673
}
670674
}
671675
});

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

+43
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import static org.mockito.Mockito.*;
2020
import static org.springframework.data.redis.core.convert.ConversionTestEntities.*;
2121

22+
import lombok.AllArgsConstructor;
23+
2224
import java.nio.charset.Charset;
2325
import java.nio.charset.StandardCharsets;
2426
import java.time.Duration;
@@ -1925,6 +1927,38 @@ void readEntityWithCustomConverter() {
19251927
assertThat(target.getAccountName()).isEqualTo("Golam Mazid Sajib");
19261928
}
19271929

1930+
@Test // GH-2349
1931+
void writeGenericEntity() {
1932+
1933+
WithGenericEntity<User> generic = new WithGenericEntity<>();
1934+
generic.entity = new User("hello");
1935+
1936+
assertThat(write(generic)).hasSize(3) //
1937+
.containsEntry("_class",
1938+
"org.springframework.data.redis.core.convert.MappingRedisConverterUnitTests$WithGenericEntity")
1939+
.containsEntry("entity.name", "hello") //
1940+
.containsEntry("entity._class",
1941+
"org.springframework.data.redis.core.convert.MappingRedisConverterUnitTests$User");
1942+
}
1943+
1944+
@Test // GH-2349
1945+
void readGenericEntity() {
1946+
1947+
Bucket bucket = new Bucket();
1948+
bucket.put("entity.name", "hello".getBytes());
1949+
bucket.put("entity._class",
1950+
"org.springframework.data.redis.core.convert.MappingRedisConverterUnitTests$User".getBytes());
1951+
1952+
RedisData redisData = new RedisData(bucket);
1953+
redisData.setKeyspace(KEYSPACE_ACCOUNT);
1954+
redisData.setId("ai-id-1");
1955+
1956+
WithGenericEntity<User> generic = converter.read(WithGenericEntity.class, redisData);
1957+
1958+
assertThat(generic.entity).isNotNull();
1959+
assertThat(generic.entity.name).isEqualTo("hello");
1960+
}
1961+
19281962
@Test // DATAREDIS-1175
19291963
@EnabledOnJre(JRE.JAVA_8)
19301964
// FIXME: https://github.com/spring-projects/spring-data-redis/issues/2168
@@ -2083,4 +2117,13 @@ public AccountInfo convert(byte[] bytes) {
20832117
}
20842118
}
20852119

2120+
static class WithGenericEntity<T> {
2121+
T entity;
2122+
}
2123+
2124+
@AllArgsConstructor
2125+
static class User {
2126+
String name;
2127+
}
2128+
20862129
}

0 commit comments

Comments
 (0)