[DATAREDIS-993] Object serialization as HashValue with StreamOperations Created: 13/Jun/19  Updated: 08/Aug/19  Resolved: 18/Jun/19

Status: Closed
Project: Spring Data Redis
Component/s: Core
Affects Version/s: 2.2 M4 (Moore)
Fix Version/s: 2.2 RC2 (Moore)

Type: Bug Priority: Major
Reporter: Romain Beghi Assignee: Mark Paluch
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Last updater: Mark Paluch
Pull Request URL: https://github.com/spring-projects/spring-data-redis/pull/455

 Description   

Given a ReactiveStreamOperations<String, String, DummyObject>, configured that way : 

@Bean
public ReactiveStreamOperations<String, String, DummyObject> createReactiveStreamOperationsForDummyObject(final ReactiveRedisConnectionFactory factory) {
  final StringRedisSerializer stringRedisSerializer = StringRedisSerializer.UTF_8;
  final Jackson2JsonRedisSerializer<DummyObject> jsonRedisSerializer = new Jackson2JsonRedisSerializer<>(DummyObject.class);

  final RedisSerializationContext.RedisSerializationContextBuilder<String, DummyObject> contextBuilder = RedisSerializationContext.newSerializationContext(stringRedisSerializer);
  final RedisSerializationContext<String, DummyObject> context = contextBuilder.hashValue(jsonRedisSerializer).build();

  return new ReactiveRedisTemplate<>(factory, context).opsForStream();
}

 

Record serialization is done here : DefaultReactiveStreamOperations.serializeRecordFields

And calls DefaultReactiveStreamOperations.rawHashKey and DefaultReactiveStreamOperations.rawValue

Where HashKey and HashValue distinct serializers are properly called.

 

 

 

However, with a StreamOperations<String, String, DummyObject>, configured that way :

@Bean
public StreamOperations<String, String, DummyObject> createStreamOperationsForDummyObject(final RedisConnectionFactory factory) {
  final StringRedisSerializer stringSerializer = StringRedisSerializer.UTF_8;
  final Jackson2JsonRedisSerializer<DummyObject> jsonSerializer = new Jackson2JsonRedisSerializer<>(DummyObject.class);

  final RedisTemplate<String, DummyObject> template = new RedisTemplate<>();
  template.setConnectionFactory(factory);
  template.setDefaultSerializer(stringSerializer);
  template.setHashValueSerializer(jsonSerializer);
  template.afterPropertiesSet();

  return template.opsForStream();
}

Serialization fails and return 

java.lang.ClassCastException: com.dummy.model.DummyObject cannot be cast to [B
org.springframework.data.redis.connection.stream.StreamSerialization.serialize(StreamSerialization.java:39)

Record serialization is done here :
MapRecord.serialize

And use fieldSerializer for both HashKey and HashValue serialization, even if its input parameters are streamSerializer, fieldSerializer and valueSerializer.

Such usage is done here :
DefaultStreamOperations.add

The fix only consists to use valueSerializer for HashValue serialization rather than fieldSerializer.

 

I'm linking to this ticket a short (and improvable) PR for this issue.  



 Comments   
Comment by Mark Paluch [ 18/Jun/19 ]

Good catch, thanks for providing a fix.

Generated at Mon Jul 06 00:41:50 UTC 2020 using Jira 8.5.4#805004-sha1:0444eab799707f9ad7b248d69f858774aadfd250.