Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01B38FGKKam5SCGgwgduVAh3
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.Serializableis rejected withSerializationException: Cannot serialize. The root cause message is Spring'sDefaultSerializer requires a Serializable payload. Nothing is written. - The same record implementing
Serializableis 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
- Use
StringRedisTemplatewhen everything is text (chapter 3). - Configure String keys and a JSON value serializer (chapter 4).
- 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
- User and SerializableUser
- DefaultTemplateTest
- Java Object Serialization Specification: stream grammar and type codes
- Spring Data Redis: serializers
Home | Prev: What Boot gives you | Next: String template and two keyspaces