Java 序列化格式
本文定义 Apache Fory Java 原生序列化格式的编码格式细节。
规范概览
Fory Java 原生格式面向 Java 对象图,支持:
- 共享引用与循环引用
- 多态对象
- 可选 schema 演进
- 流式写入(共享 type meta 按需内联,不要求预先 meta 区)
Java native 是 xlang 编码格式的扩展,复用相同核心帧与基础编码。
总体布局:
| fory header | object ref meta | object type meta | object value data |
字节序统一为 little-endian。大端平台实现需在数组等路径做字节序转换,确保线上格式一致。
Fory 头部
Java 原生序列化头部是 1-byte 位图:
| 5 bits | 1 bit | 1 bit | 1 bit |
+--------------+-------+-------+-------+
| reserved | oob | xlang | null |
含义:
null:对象是否为 null(为 1 时其余位不应置位)xlang:1 表示 xlang 格式,0 表示 Java nativeoob:1 表示存在BufferCallback
头部始终 1 字节,不额外写 language ID。
引用元信息
引用跟踪标记与 xlang 一 致:
| 标记 | 字节值 | 说明 |
|---|---|---|
| NULL FLAG | -3 | 对象为 null,后续不写对象内容 |
| REF FLAG | -2 | 已出现对象,后接 varuint32 的 reference ID |
| NOT_NULL VALUE FLAG | -1 | 非空但该类型未启用引用跟踪,后接对象内容 |
| REF VALUE FLAG | 0 | 可引用对象首次出现,后接对象内容,并分配新 reference ID |
当全局或字段级禁用引用跟踪时,仅使用 NULL FLAG 与 NOT_NULL VALUE FLAG。
Type system and type IDs
Java native 使用与 xlang 统一的类型 ID 组合方式:
full_type_id = (user_type_id << 8) | internal_type_id
internal_type_id:低 8 位,表示类型种类user_type_id:用户注册数值 ID(适用于用户 enum/struct/ext)- named 类型使用
NAMED_*,其标识来自元信息(命名空间+类型名)
Shared internal type IDs (0-63)
Java native 与 xlang 共享 < 64 的 internal IDs:
0~56已定义57~63预留
详见 Xlang Serialization Format。
Java native built-in type IDs
Java 专有内建类型从 Types.BOUND + 5 开始(Types.BOUND=64,预留 5 个)。
| Type ID | Name | Description |
|---|---|---|
| 69 | VOID_ID | java.lang.Void |
| 70 | CHAR_ID | java.lang.Character |
| 71 | PRIMITIVE_VOID_ID | void |
| 72 | PRIMITIVE_BOOL_ID | boolean |
| 73 | PRIMITIVE_INT8_ID | byte |
| 74 | PRIMITIVE_CHAR_ID | char |
| 75 | PRIMITIVE_INT16_ID | short |
| 76 | PRIMITIVE_INT32_ID | int |
| 77 | PRIMITIVE_FLOAT32_ID | float |
| 78 | PRIMITIVE_INT64_ID | long |
| 79 | PRIMITIVE_FLOAT64_ID | double |
| 80 | PRIMITIVE_BOOLEAN_ARRAY_ID | boolean[] |
| 81 | PRIMITIVE_BYTE_ARRAY_ID | byte[] |
| 82 | PRIMITIVE_CHAR_ARRAY_ID | char[] |
| 83 | PRIMITIVE_SHORT_ARRAY_ID | short[] |
| 84 | PRIMITIVE_INT_ARRAY_ID | int[] |
| 85 | PRIMITIVE_FLOAT_ARRAY_ID | float[] |
| 86 | PRIMITIVE_LONG_ARRAY_ID | long[] |
| 87 | PRIMITIVE_DOUBLE_ARRAY_ID | double[] |
| 88 | STRING_ARRAY_ID | String[] |
| 89 | OBJECT_ARRAY_ID | Object[] |
| 90 | ARRAYLIST_ID | java.util.ArrayList |
| 91 | HASHMAP_ID | java.util.HashMap |
| 92 | HASHSET_ID | java.util.HashSet |
| 93 | CLASS_ID | java.lang.Class |
| 94 | EMPTY_OBJECT_ID | empty object stub |
| 95 | LAMBDA_STUB_ID | lambda stub |
| 96 | JDK_PROXY_STUB_ID | JDK proxy stub |
| 97 | REPLACE_STUB_ID | writeReplace/readResolve stub |
| 98 | NONEXISTENT_META_SHARED_ID | meta-shared unknown class stub |
Registration and named types
用户类型可按数值或名称注册:
- 数值注册:
full_type_id = (user_id << 8) | internal_type_id - 名称注册:通过 namespace + typename
- 未注册类型按 named 类型写出(namespace=包名,typename=类名)
未注册时命名类型选择:
- enum ->
NAMED_ENUM - struct-like ->
NAMED_STRUCT(兼容模式下NAMED_COMPATIBLE_STRUCT) - 其他自定义 serializer ->
NAMED_EXT
Type meta encoding
每个值写入流程:
- 写
type_id(varuint32 small7) - 对
NAMED_*/COMPATIBLE_STRUCT等类型按规则写额外元信息 - 其余类型无需额外 meta
Shared class meta (streaming)
开启 meta share 时,使用流式共享 class meta:
| varuint32: index_marker | [class def bytes if new] |
index_marker = (index << 1) | flag
flag = 1 -> reference
flag = 0 -> new type
flag=1:引用历史 type,后续无 class def bytesflag=0:新 type,后续内联 class def- index 按首次出现顺序递增
Schema modes
Java native 支持两种模式:
- Schema consistent(compatible 关闭):字段按固定顺序写,不需要 ClassDef
- Schema evolution(compatible 开启):按 ClassDef 元信息支持演进
ClassDef format (compatible mode)
ClassDef 是 compatible struct 的演进元信息。
Binary layout
| 8 bytes header | [varuint32 extra size] | class meta bytes |
header 位布局:
| 50-bit hash | 4 bits reserved | 1 bit compress | 1 bit has_fields_meta | 8-bit size |
规则:
size为低 8 位;若为0xFF