[Home](../README.md) | Prev: [What Boot gives you](01-what-boot-gives-you.md) | Next: [String template and two keyspaces](03-string-template-and-two-keyspaces.md) # 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`, uses `JdkSerializationRedisSerializer` for keys **and** values ([01-default-template.txt](output/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](output/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](output/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](03-string-template-and-two-keyspaces.md)). 2. Configure String keys and a JSON value serializer ([chapter 4](04-json-serializers.md)). 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 - [User](../src/main/java/com/ankurm/redis/model/User.java) and [SerializableUser](../src/main/java/com/ankurm/redis/model/SerializableUser.java) - [DefaultTemplateTest](../src/test/java/com/ankurm/redis/DefaultTemplateTest.java) - [Java Object Serialization Specification: stream grammar and type codes](https://docs.oracle.com/en/java/javase/25/docs/specs/serialization/protocol.html) - [Spring Data Redis: serializers](https://docs.spring.io/spring-data/redis/reference/redis/template.html#redis:serializer) [Home](../README.md) | Prev: [What Boot gives you](01-what-boot-gives-you.md) | Next: [String template and two keyspaces](03-string-template-and-two-keyspaces.md)