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
This commit is contained in:
Mark Paluch
2022-04-20 15:16:50 +02:00
parent e0f49370d9
commit 5f75eab65e
2 changed files with 12 additions and 7 deletions

View File

@@ -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;

View File

@@ -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<String, String> 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<Person> 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<Object> source = Arrays.asList("Hello", "stream", "message", 100L);
List<Object> source = Arrays.asList("Hello", "stream", "message", 100L);
RedisTestData target = write(source);
assertThat(target).containsEntry("[0]", "Hello") //