diff --git a/src/main/asciidoc/reference/redis-streams.adoc b/src/main/asciidoc/reference/redis-streams.adoc index 1e3906bcb..254bbb6f1 100644 --- a/src/main/asciidoc/reference/redis-streams.adoc +++ b/src/main/asciidoc/reference/redis-streams.adoc @@ -293,3 +293,37 @@ redisTemplate() .add(record); <1> ---- <1> XADD user-logon * "firstname" "night" "@class" "com.example.User" "lastname" "angel" + +[NOTE] +==== +A `StreamMessageListenerContainer` may not be aware of any `@TypeAlias` used on domain types as those need to be resolved via a `MappingContext`. So please make sure to pre initialize the `RedisMappingContext` with the `initialEntitySet`. + +[source,java] +---- +@Bean +RedisMappingContext redisMappingContext() { + RedisMappingContext ctx = new RedisMappingContext(); + ctx.setInitialEntitySet(Collections.singleton(Person.class)); + return ctx; +} + +@Bean +RedisConverter redisConverter(RedisMappingContext mappingContext) { + return new MappingRedisConverter(mappingContext, null, null); +} + +@Bean +ObjectHashMapper hashMapper(RedisConverter converter) { + return new ObjectHashMapper(converter); +} + +@Bean +StreamMessageListenerContainer streamMessageListenerContainer(RedisConnectionFactory connectionFactory, ObjectHashMapper hashMapper) { + StreamMessageListenerContainerOptions> options = StreamMessageListenerContainerOptions.builder() + .objectMapper(hashMapper) + .build(); + + return StreamMessageListenerContainer.create(connectionFactory, options); +} +---- +==== diff --git a/src/main/java/org/springframework/data/redis/hash/ObjectHashMapper.java b/src/main/java/org/springframework/data/redis/hash/ObjectHashMapper.java index f0f0c4257..bed73efe8 100644 --- a/src/main/java/org/springframework/data/redis/hash/ObjectHashMapper.java +++ b/src/main/java/org/springframework/data/redis/hash/ObjectHashMapper.java @@ -16,24 +16,21 @@ package org.springframework.data.redis.hash; import java.util.Collections; -import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; -import org.springframework.core.convert.ConverterNotFoundException; -import org.springframework.data.mapping.PropertyPath; -import org.springframework.data.mapping.PropertyReferenceException; import org.springframework.data.redis.core.convert.CustomConversions; import org.springframework.data.redis.core.convert.IndexResolver; import org.springframework.data.redis.core.convert.IndexedData; import org.springframework.data.redis.core.convert.MappingRedisConverter; +import org.springframework.data.redis.core.convert.RedisConverter; import org.springframework.data.redis.core.convert.RedisCustomConversions; import org.springframework.data.redis.core.convert.RedisData; import org.springframework.data.redis.core.convert.ReferenceResolver; import org.springframework.data.redis.core.mapping.RedisMappingContext; -import org.springframework.data.redis.core.mapping.RedisPersistentEntity; import org.springframework.data.util.TypeInformation; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; /** * {@link HashMapper} based on {@link MappingRedisConverter}. Supports nested properties and simple types like @@ -74,7 +71,7 @@ import org.springframework.lang.Nullable; */ public class ObjectHashMapper implements HashMapper { - private final MappingRedisConverter converter; + private final RedisConverter converter; /** * Creates new {@link ObjectHashMapper}. @@ -110,6 +107,19 @@ public class ObjectHashMapper implements HashMapper { converter = mappingConverter; } + /** + * Creates a new {@link ObjectHashMapper} using the given {@link RedisConverter} for conversion. + * + * @param converter must not be {@literal null}. + * @throws IllegalArgumentException if the given {@literal converter} is {@literal null}. + * @since 2.4 + */ + public ObjectHashMapper(RedisConverter converter) { + + Assert.notNull(converter, "Converter must not be null!"); + this.converter = converter; + } + /* * (non-Javadoc) * @see org.springframework.data.redis.hash.HashMapper#toHash(java.lang.Object) diff --git a/src/test/java/org/springframework/data/redis/mapping/ObjectHashMapperTests.java b/src/test/java/org/springframework/data/redis/mapping/ObjectHashMapperTests.java index 903f15536..9e3f20830 100644 --- a/src/test/java/org/springframework/data/redis/mapping/ObjectHashMapperTests.java +++ b/src/test/java/org/springframework/data/redis/mapping/ObjectHashMapperTests.java @@ -17,10 +17,15 @@ package org.springframework.data.redis.mapping; import static org.assertj.core.api.Assertions.*; +import lombok.Data; + +import java.util.Collections; import java.util.Map; import org.junit.Test; - +import org.springframework.data.annotation.TypeAlias; +import org.springframework.data.redis.core.convert.MappingRedisConverter; +import org.springframework.data.redis.core.mapping.RedisMappingContext; import org.springframework.data.redis.hash.ObjectHashMapper; /** @@ -57,4 +62,29 @@ public class ObjectHashMapperTests extends AbstractHashMapperTest { String result = objectHashMapper.fromHash(hash, String.class); } + + @Test // DATAREDIS-1179 + public void hashMapperAllowsReuseOfRedisConverter/*and thus the MappingContext holding eg. TypeAlias information*/() { + + WithTypeAlias source = new WithTypeAlias(); + source.value = "val"; + Map hash = new ObjectHashMapper().toHash(source); + + RedisMappingContext ctx = new RedisMappingContext(); + ctx.setInitialEntitySet(Collections.singleton(WithTypeAlias.class)); + ctx.afterPropertiesSet(); + + MappingRedisConverter mappingRedisConverter = new MappingRedisConverter(ctx, null, null); + mappingRedisConverter.afterPropertiesSet(); + + ObjectHashMapper objectHashMapper = new ObjectHashMapper(mappingRedisConverter); + assertThat(objectHashMapper.fromHash(hash)).isEqualTo(source); + } + + @TypeAlias("_42_") + @Data + static class WithTypeAlias { + String value; + } + }