Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01B38FGKKam5SCGgwgduVAh3
70 lines
3.6 KiB
Markdown
70 lines
3.6 KiB
Markdown
[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<Object, Object>`,
|
|
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)
|