Files
spring-boot-demo/redis/docs/02-default-serialization.md

3.6 KiB

Home | Prev: What Boot gives you | Next: String template and two keyspaces

2. Default serialization: why redis-cli shows garbage

Redis stores bytes. A RedisTemplate is a translator between Java objects and those bytes, and the translator is a RedisSerializer. The template Boot registers, RedisTemplate<Object, Object>, uses JdkSerializationRedisSerializer for keys and values (01-default-template.txt):

key serializer:   JdkSerializationRedisSerializer
value serializer: JdkSerializationRedisSerializer

What lands in Redis

redisTemplate.opsForValue().set("user:1", "Ankur") stores this key, which is not user:1:

$ redis-cli -p 6390 --no-raw KEYS '*'
1) "\xac\xed\x00\x05t\x00\x06user:1"
$ redis-cli -p 6390 --no-raw GET user:1
(nil)

Reading the bytes: \xac\xed\x00\x05 is the header of every Java serialization stream (magic number 0xACED, stream version 5). t is the type code for a string, \x00\x06 its length, then the six characters. Java wrote a serialised String object, not the characters. GET user:1 therefore misses: a different key.

The value is the same story ("\xac\xed\x00\x05t\x00\x05Ankur"), and Java reading it back through the same template works, which is why the problem hides: every test that goes through the template passes.

What it does to objects

02-default-template-not-serializable.txt:

  • A record that is not java.io.Serializable is rejected with SerializationException: Cannot serialize. The root cause message is Spring's DefaultSerializer requires a Serializable payload. Nothing is written.
  • The same record implementing Serializable is accepted, and the stored bytes contain the fully qualified class name (com.ankurm.redis.model.SerializableUser) and field descriptors. Rename or move the class and existing entries stop deserializing.

The counter trap

opsForValue().increment("hits") sends INCR, and Redis stores the text 1. The template wrote the key with JDK serialization, but the counter's value is plain text, so the next get fails (03-default-template-increment.txt):

org.springframework.data.redis.serializer.SerializationException
  message: Cannot deserialize
  root:    java.io.EOFException: null

Any command where Redis itself interprets the value (INCR, INCRBYFLOAT, HINCRBY) needs a serializer that writes plain text.

Fixes

  1. Use StringRedisTemplate when everything is text (chapter 3).
  2. Configure String keys and a JSON value serializer (chapter 4).
  3. If data written with the JDK serializer is already in production, changing the serializer orphans it: new keys have different bytes. Plan a migration or a new key prefix. This repository does not exercise a migration.

Going deeper

Home | Prev: What Boot gives you | Next: String template and two keyspaces