serialization: Java serialization companion code (UID drift, JEP 290/415 filters, records, JSON/Protobuf comparison)

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01KqJyCidz3ZgRyHABv2GVJh
This commit is contained in:
Claude
2026-09-30 19:03:40 +00:00
parent b31c6716a3
commit 97e7352f45
31 changed files with 867 additions and 0 deletions
@@ -0,0 +1,4 @@
declared serialVersionUID = 1
UID found in the stream = 1
patched stream UID = 2
InvalidClassException: com.ankurm.serialization.UidInStreamDemo$Ticket; local class incompatible: stream classdesc serialVersionUID = 2, local class serialVersionUID = 1
@@ -0,0 +1,6 @@
$ # implicit serialVersionUID (none declared)
$ java -cp v1 DriftWrite
wrote 113 bytes; serialVersionUID in stream = 1201216851776330172
$ java -cp v2 DriftRead # v2 adds a field
this class's serialVersionUID = -732213015030957059
InvalidClassException: com.ankurm.serialization.drift.Account; local class incompatible: stream classdesc serialVersionUID = 1201216851776330172, local class serialVersionUID = -732213015030957059
@@ -0,0 +1,6 @@
$ # explicit serialVersionUID = 1L
$ java -cp v1 DriftWrite
wrote 113 bytes; serialVersionUID in stream = 1
$ java -cp v2 DriftRead # v2 adds a field
this class's serialVersionUID = 1
read: Account[owner=asha, balance=500, email=null]
@@ -0,0 +1,6 @@
application expects a Greeting and writes: String greeting = (Greeting) in.readObject()
>>> Noisy.readObject() is running -- code of the class named in the stream
ClassCastException AFTER the side effect: class com.ankurm.serialization.ReadObjectRunsCodeDemo$Noisy cannot be cast to class com.ankurm.serialization.ReadObjectRunsCodeDemo$Greeting (com.ankurm.serialization.ReadObjectRunsCodeDemo$Noisy and com.ankurm.serialization.ReadObjectRunsCodeDemo$Greeting are in unnamed module of loader 'app')
same bytes, allow-list filter that only admits Greeting:
InvalidClassException: filter status: REJECTED
@@ -0,0 +1,16 @@
max heap = 256 MiB
forged stream is 37 bytes long but claims a byte[1000000000]
no filter -> OutOfMemoryError: Java heap space
maxarray=100000 -> InvalidClassException: filter status: REJECTED
filter saw: class=class [B arrayLength=-1 depth=1 streamBytes=21 -> UNDECIDED
filter saw: class=class [B arrayLength=1000000000 depth=1 streamBytes=27 -> REJECTED
maxarray, logged -> InvalidClassException: filter status: REJECTED
a legitimate-looking chain of 200 nodes is 1324 bytes
no filter -> accepted: Node
maxdepth=50 -> InvalidClassException: filter status: REJECTED
maxbytes=10000, one 50 KB array -> accepted: byte[]
an ArrayList of 5000 integers is 50125 bytes
maxbytes=10000, 5000 integers -> InvalidClassException: filter status: REJECTED
maxbytes=1000000, 5000 integers -> accepted: ArrayList
+5
View File
@@ -0,0 +1,5 @@
record default serialVersionUID = 0
forged stream with years = -5:
record -> InvalidObjectException: years out of range: -5
cause: java.lang.IllegalArgumentException: years out of range: -5
class -> AgeClass[years=-5] (no constructor ran)
@@ -0,0 +1,13 @@
$ java -Djdk.serialFilter="maxdepth=10;com.ankurm.serialization.*;java.lang.*;!*" FilterFactoryDemo
jdk.serialFilter (system property) = maxdepth=10;com.ankurm.serialization.*;java.lang.*;!*
Config.getSerialFilter() = maxdepth=10;com.ankurm.serialization.*;java.lang.*;!*
factory before = java.io.ObjectInputFilter$Config$BuiltinFilterFactory
factory installed; installing a second one:
IllegalStateException: Cannot replace filter factory
context A (Ok + String allowed):
read Ok -> Ok[s=fine]
read String -> a plain string
read 50-deep chain -> InvalidClassException: filter status: REJECTED
context B (String only):
read String -> a plain string
read Ok -> InvalidClassException: filter status: REJECTED
+10
View File
@@ -0,0 +1,10 @@
Java serialization : 382 bytes, starts with aced0005 (magic aced0005)
Jackson 3 JSON : 223 bytes
Protobuf wire : 80 bytes
JSON text: {"id":1000042,"customer":"Asha Mehta","currency":"INR","lines":[{"sku":"BK-JAVA-25","quantity":2,"priceMinor":49900},{"sku":"BK-JVM-INT","quantity":1,"priceMinor":79900},{"sku":"CBL-USB-C","quantity":3,"priceMinor":19900}]}
round trips equal : java=true json=true protobuf=true
JSON cannot name a class to instantiate unless you opt in. Feeding it a type hint:
parsed as Order[id=1, customer=x, currency=INR, lines=[]]
+4
View File
@@ -0,0 +1,4 @@
Benchmark Mode Cnt Score Error Units
SerializationBenchmark.jacksonJson avgt 16 3107.305 ± 467.508 ns/op
SerializationBenchmark.javaSerialization avgt 16 11316.514 ± 538.967 ns/op
SerializationBenchmark.protobufWire avgt 16 3736.484 ± 283.111 ns/op
+4
View File
@@ -0,0 +1,4 @@
-------------------------------------------------------------------------------
Test set: com.ankurm.serialization.SerializationTest
-------------------------------------------------------------------------------
Tests run: 11, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.851 s -- in com.ankurm.serialization.SerializationTest