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 54e19a997..b26e28a5d 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 @@ -56,6 +56,7 @@ import org.springframework.data.redis.core.mapping.RedisPersistentEntity; import org.springframework.data.redis.core.mapping.RedisPersistentProperty; import org.springframework.data.redis.util.ByteUtils; import org.springframework.data.util.ClassTypeInformation; +import org.springframework.data.util.ProxyUtils; import org.springframework.data.util.TypeInformation; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -258,12 +259,20 @@ public class MappingRedisConverter implements RedisConverter, InitializingBean { protected Object readProperty(String path, RedisData source, RedisPersistentProperty persistentProperty) { String currentPath = !path.isEmpty() ? path + "." + persistentProperty.getName() : persistentProperty.getName(); + TypeInformation typeInformation = typeMapper.readType(source.getBucket().getPropertyPath(currentPath), + persistentProperty.getTypeInformation()); - TypeInformation typeInformation = persistentProperty.getTypeInformation(); + if (typeInformation.isMap()) { - if (persistentProperty.isMap()) { + Class mapValueType = null; - Class mapValueType = persistentProperty.getMapValueType(); + if (typeInformation.getMapValueType() != null) { + mapValueType = typeInformation.getMapValueType().getType(); + } + + if (mapValueType == null && persistentProperty.isMap()) { + mapValueType = persistentProperty.getMapValueType(); + } if (mapValueType == null) { throw new IllegalArgumentException("Unable to retrieve MapValueType"); @@ -293,16 +302,14 @@ public class MappingRedisConverter implements RedisConverter, InitializingBean { } } - if (persistentProperty.isEntity() + if (mappingContext.getPersistentEntity(typeInformation) != null && !conversionService.canConvert(byte[].class, typeInformation.getRequiredActualType().getType())) { Bucket bucket = source.getBucket().extract(currentPath + "."); RedisData newBucket = new RedisData(bucket); - TypeInformation typeToRead = typeMapper.readType(bucket.getPropertyPath(currentPath), - typeInformation); - return readInternal(currentPath, typeToRead.getType(), newBucket); + return readInternal(currentPath, typeInformation.getType(), newBucket); } byte[] sourceBytes = source.getBucket().get(currentPath); @@ -580,8 +587,7 @@ public class MappingRedisConverter implements RedisConverter, InitializingBean { * @param sink */ private void writeInternal(@Nullable String keyspace, String path, @Nullable Object value, - TypeInformation typeHint, - RedisData sink) { + TypeInformation typeHint, RedisData sink) { if (value == null) { return; @@ -656,17 +662,15 @@ public class MappingRedisConverter implements RedisConverter, InitializingBean { } } - } else if (persistentProperty.isEntity()) { + } else if (propertyValue != null) { - if (propertyValue != null) { + if (customConversions.isSimpleType(ProxyUtils.getUserClass(propertyValue.getClass()))) { + + writeToBucket(propertyStringPath, propertyValue, sink, persistentProperty.getType()); + } else { writeInternal(keyspace, propertyStringPath, propertyValue, persistentProperty.getTypeInformation().getRequiredActualType(), sink); } - } else { - - if (propertyValue != null) { - writeToBucket(propertyStringPath, propertyValue, sink, persistentProperty.getType()); - } } }); 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 7ed682386..01a909b7e 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 @@ -19,6 +19,8 @@ import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; import static org.springframework.data.redis.core.convert.ConversionTestEntities.*; +import lombok.AllArgsConstructor; + import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.time.Duration; @@ -1925,6 +1927,38 @@ class MappingRedisConverterUnitTests { assertThat(target.getAccountName()).isEqualTo("Golam Mazid Sajib"); } + @Test // GH-2349 + void writeGenericEntity() { + + WithGenericEntity generic = new WithGenericEntity<>(); + generic.entity = new User("hello"); + + assertThat(write(generic)).hasSize(3) // + .containsEntry("_class", + "org.springframework.data.redis.core.convert.MappingRedisConverterUnitTests$WithGenericEntity") + .containsEntry("entity.name", "hello") // + .containsEntry("entity._class", + "org.springframework.data.redis.core.convert.MappingRedisConverterUnitTests$User"); + } + + @Test // GH-2349 + void readGenericEntity() { + + Bucket bucket = new Bucket(); + bucket.put("entity.name", "hello".getBytes()); + bucket.put("entity._class", + "org.springframework.data.redis.core.convert.MappingRedisConverterUnitTests$User".getBytes()); + + RedisData redisData = new RedisData(bucket); + redisData.setKeyspace(KEYSPACE_ACCOUNT); + redisData.setId("ai-id-1"); + + WithGenericEntity generic = converter.read(WithGenericEntity.class, redisData); + + assertThat(generic.entity).isNotNull(); + assertThat(generic.entity.name).isEqualTo("hello"); + } + @Test // DATAREDIS-1175 @EnabledOnJre(JRE.JAVA_8) // FIXME: https://github.com/spring-projects/spring-data-redis/issues/2168 @@ -2083,4 +2117,13 @@ class MappingRedisConverterUnitTests { } } + static class WithGenericEntity { + T entity; + } + + @AllArgsConstructor + static class User { + String name; + } + }