From 5f75eab65eb19b16d46b6e60c374f5e7696567db Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 20 Apr 2022 15:16:50 +0200 Subject: [PATCH] Attempt early usage of custom converters. We now try to eagerly apply a custom converter when reading Redis properties in the MappingRedisConverter before considering type hints from the hash. We require type hints to properly restore the target type for a hash entry as Redis data is all byte arrays, so a simple String needs a type hint before we can load it back into an e.g. Object-typed property. Subtypes of properties (such as ZoneRegion for ZoneId) are sometimes not associated with a converter as only the parent type (ZoneId) is associated with a converter. Trying to convert the value into the subtype directly through our ConversionService would fail in that case. Closes #2307 --- .../redis/core/convert/MappingRedisConverter.java | 7 +++++-- .../core/convert/MappingRedisConverterUnitTests.java | 12 +++++++----- 2 files changed, 12 insertions(+), 7 deletions(-) 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 8233e3496..24e2ea672 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 @@ -319,6 +319,10 @@ public class MappingRedisConverter implements RedisConverter, InitializingBean { return null; } + if (customConversions.hasCustomReadTarget(byte[].class, persistentProperty.getType())) { + return fromBytes(sourceBytes, persistentProperty.getType()); + } + Class typeToUse = getTypeHint(currentPath, source.getBucket(), persistentProperty.getType()); return fromBytes(sourceBytes, typeToUse); } @@ -728,8 +732,7 @@ public class MappingRedisConverter implements RedisConverter, InitializingBean { * @param sink */ private void writeCollection(@Nullable String keyspace, String path, @Nullable Iterable values, - TypeInformation typeHint, - RedisData sink) { + TypeInformation typeHint, RedisData sink) { if (values == null) { return; 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 055413c69..7ed682386 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 @@ -696,11 +696,14 @@ class MappingRedisConverterUnitTests { assertThat(write(rand)).containsEntry("zoneId", "Europe/Paris"); } - @Test // DATAREDIS-425 + @Test // DATAREDIS-425, GH-2307 void readsZoneIdValuesCorrectly() { - Person target = converter.read(Person.class, - new RedisData(Bucket.newBucketFromStringMap(Collections.singletonMap("zoneId", "Europe/Paris")))); + Map map = new HashMap<>(); + map.put("zoneId", "Europe/Paris"); + map.put("zoneId._class", "java.time.ZoneRegion"); + + Person target = converter.read(Person.class, new RedisData(Bucket.newBucketFromStringMap(map))); assertThat(target.zoneId).isEqualTo(ZoneId.of("Europe/Paris")); } @@ -1790,7 +1793,6 @@ class MappingRedisConverterUnitTests { @Test // DATAREDIS-471 void writeShouldThrowExceptionForUpdateValueInCollectionNotAssignableToDomainTypeProperty() { - PartialUpdate update = new PartialUpdate<>("123", Person.class) // .set("coworkers", Collections.singletonList("foo")); @@ -1928,7 +1930,7 @@ class MappingRedisConverterUnitTests { // FIXME: https://github.com/spring-projects/spring-data-redis/issues/2168 void writePlainList() { - List source = Arrays.asList("Hello", "stream", "message", 100L); + List source = Arrays.asList("Hello", "stream", "message", 100L); RedisTestData target = write(source); assertThat(target).containsEntry("[0]", "Hello") //