skip to Main Content

I’m trying to parse objects from a Redis stream via Spring Boot Reactive Redis that are added by an external service. I’m using the following the tutorial to retrieve the elements from the stream via a StreamListener<String, ObjectRecord<String, TestDTO>>.

The object in the Redis stream consists of an id, a number and a Protobuf byte array (which is produced from a Python service via SerializeToString())

The Redis data retrieved via the redis-cli looks like this:

1) "1234567891011-0"
   2) 1) "id"
      2) "f63c2bcd...."
      3) "number"
      4) "5"
      5) "raw_data"
      6) "bx01x12...

I’ve created the following DTO to match the objects in the Redis stream:

@Data
@NoArgsConstructor
public class TestDTO {
    private UUID id;
    private long number;
    private byte[] raw_data;
}

However this throws the following error:

org.springframework.core.convert.ConversionFailedException: Failed to convert from type [org.springframework.data.redis.connection.stream.StreamRecords$ByteMapBackedRecord] to type [com.test.test.TestDTO] for value 'MapBackedRecord{recordId=1647417370847-0, kvMap={[B@2beed3c=[B@523baefb, [B@76cea664=[B@62358d82, [B@7ad95089=[B@35d4c48e}}'; nested exception is java.lang.IllegalArgumentException: Value must not be null!

Reading it a as generic MapRecord<String, String, String> works without any problem, but converting it directly to an Object would make for cleaner code. I have the feeling that I need to specify a deserializer, but I haven’t found out yet, how to do that. Any recommendations on how to tackle this issue would be more than welcome!

2

Answers


  1. You need to specify a RedisTemplate bean, where you can specify the Key/Value serialization/deserialization. In your case probably you should use GenericJackson2JsonRedisSerializer.

    Example using StringRedisSerializer:

      @Bean
      public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, String> template = new RedisTemplate<>();
    
        template.setConnectionFactory(connectionFactory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new StringRedisSerializer());
        template.afterPropertiesSet();
    
        return template;
      }
    

    RedisTemplate javadoc: https://docs.spring.io/spring-data/redis/docs/current/api/org/springframework/data/redis/core/RedisTemplate.html

    Spring Data Redis documentation: https://docs.spring.io/spring-data/redis/docs/current/reference/html/

    Available serializers: https://docs.spring.io/spring-data/redis/docs/current/reference/html/#redis:serializer

    This question can also help you: RedisTemplate hashvalue serializer to use for nested object with multiple types

    Login or Signup to reply.
  2. It seems:

    StreamListener<String, ObjectRecord<String, SomeDTO>>

    is not available in spring-boot 3.

    In my case I was using spring-boot version 3.0.0 and even upgraded to 3.0.1.
    I noticed this same issue in these spring-boot versions. I fixed it by adding a spring-data-redis dependency and specifying the version as any of the older 2.x.x versions

    Previous POM.xml

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    

    New POM.xml

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-redis</artifactId>
        <version>2.7.7</version>
    </dependency>
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search