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:
@@ -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
|
||||
@@ -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
|
||||
@@ -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=[]]
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user