spring-projects / spring-data-redis

Provides support to increase developer productivity in Java when using Redis, a key-value store. Uses familiar Spring concepts such as a template classes for core API usage and lightweight repository style data access.
https://spring.io/projects/spring-data-redis/
Apache License 2.0
1.75k stars 1.16k forks source link

Custom HashValueSerializer for RedisTemplate in redis stream happend ConversionFailedException! #2391

Open sccassiel opened 2 years ago

sccassiel commented 2 years ago

in my configclass,code show as below

@Bean
public GenericJackson2JsonRedisSerializer jsonRedisSerializer(
        Jackson2ObjectMapperBuilder objectMapperBuilder) {
    var objectMapper = objectMapperBuilder.build();
    GenericJackson2JsonRedisSerializer.registerNullValueSerializer(objectMapper, null);
    objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(),
            ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
    return new GenericJackson2JsonRedisSerializer(objectMapper);
}

@Bean
public RedisTemplate<String, Object> redisTemplate(
        RedisConnectionFactory redisConnectionFactory,
        GenericJackson2JsonRedisSerializer jsonRedisSerializer) {
    var template = new RedisTemplate<String, Object>();
    template.setConnectionFactory(redisConnectionFactory);
    template.setKeySerializer(RedisSerializer.string());
    template.setValueSerializer(jsonRedisSerializer);
    template.setHashKeySerializer(RedisSerializer.string());
    template.setHashValueSerializer(jsonRedisSerializer);
    return template;
}

public class ConsumerListener implements StreamListener<String, ObjectRecord<String, ModelMessageBO>> {
    private String group;
    private String topic;
    private RedisTemplate<String, Object> redisTemplate;
    private AbstractModelMessageHandler modelMessageHandler;
    public ModelJobConsumerListener(String topic, String group, RedisTemplate<String, Object> redisTemplate, AbstractModelMessageHandler modelMessageHandler) {
        this.topic = topic;
        this.group = group;
        this.redisTemplate = redisTemplate;
        this.modelMessageHandler = modelMessageHandler;
    }

  @Override
  public void onMessage(ObjectRecord message) {
     Object value=message.getValue();
  }

}

If i use template.setHashValueSerializer(jsonRedisSerializer),an ConversionFailedException occurs. But i use template.setHashValueSerializer(RedisSerializer.string()) ,it working normally. Is it a bug🐛? Thank you.

schauder commented 2 years ago

Please provide a Minimimal Reproducable Example, preferable as a Github repository.

sccassiel commented 2 years ago

Please provide a Minimimal Reproducable Example, preferable as a Github repository.

you can run demo: https://github.com/sccassiel/demo ,please!

mp911de commented 1 year ago

Hash- and stream serializers are used to serialize keys and values into Map-like structures. With Redis Streams, objects are decomposed into properties and the actual property values get serialized with the serializer. Converting a String into JSON doesn't make really sense as the result doesn't represent the intention.

127.0.0.1:6379> xrange stream-key - +
1) 1) "1666094363234-0"
   2) 1) "_class"
      2) "\"Y29tLmV4YW1wbGUuZGVtby5iby5NZXNzYWdlQk8=\""
      3) "id"
      4) "\"MQ==\""
      5) "message"
      6) "\"dGVzdCBtZXNzYWdl\""
mp911de commented 1 year ago

It is a bit unfortunate that Jackson renders byte arrays as Base64, and we cannot read those back in. I'll take this item to the team to see whether we can improve.