Hessian 2.0 序列化协议

Hessian是一种轻量、快速的web协议,在微服务场景下经常被使用。

Hessian协议实际上包含两种含义:

1. Web网络通信远程调用服务,具体可以参考:http://hessian.caucho.com/doc/hessian-ws.html

2. 数据序列化协议,即本篇文章的内容,原文来自于:http://hessian.caucho.com/doc/hessian-serialization.html

Hessian的Web通讯协议中实际上包含了Hessian序列化的内容,但Hessian序列化协议又不仅可以用于Hessian通讯协议。

例如dubbo的默认通讯协议基于dubbo,但同时使用的又是Hessian2的序列化协议。

可以参考Dubbo官网的图片:

其中Serialization可以使用Hessian序列化协议进行序列化。

下面我们进入正题吧:

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 

Hessian 2.0 Serialization Protocol

本备忘录的状态

通过提交此互联网草案,每位作者表示他或她知道已经或将要披露的任何适用的专利或其他知识产权权利要求,并且根据第6节将披露他或她知晓的任何权利要求。 BCP 79。

Internet-Drafts是Internet工程任务组(IETF)及其工作组的工作文档。 请注意,其他组也可能将工作文档分发为Internet-Drafts。

互联网草案是有效期最长为六个月的草案文件,可能随时被其他文件更新,替换或废弃。 使用互联网草稿作为参考资料或引用它们而不是“正在进行的工作”是不恰当的

可以在 http://www.ietf.org/ietf/1id-abstracts.txt 上访问当前的Internet草案列表。

可以在 http://www.ietf.org/shadow.html 上访问Internet-Draft Shadow目录列表。

此互联网草案将于2008年2月2日到期。

目录:

1.  Introduction
2.  Design Goals
3.  Hessian Grammar
4.  Serialization
    4.1.  binary data
        4.1.1.  Compact: short binary
        4.1.2.  Binary Examples
    4.2.  boolean
        4.2.1.  Boolean Examples
    4.3.  date
        4.3.1.  Compact: date in minutes
        4.3.2.  Date Examples
    4.4.  double
        4.4.1.  Compact: double zero
        4.4.2.  Compact: double one
        4.4.3.  Compact: double octet
        4.4.4.  Compact: double short
        4.4.5.  Compact: double float
        4.4.6.  Double Examples
    4.5.  int
        4.5.1.  Compact: single octet integers
        4.5.2.  Compact: two octet integers
        4.5.3.  Compact: three octet integers
        4.5.4.  Integer Examples
    4.6.  list
        4.6.1.  Compact: fixed length list
        4.6.2.  List examples
    4.7.  long
        4.7.1.  Compact: single octet longs
        4.7.2.  Compact: two octet longs
        4.7.3.  Compact: three octet longs
        4.7.4.  Compact: four octet longs
        4.7.5.  Long Examples
    4.8.  map
        4.8.1.  Map examples
    4.9.  null
    4.10.  object
        4.10.1.  Compact: class definition
        4.10.2.  Compact: object instantiation
        4.10.3.  Object examples
    4.11.  ref
        4.11.1.  Ref Examples
    4.12.  string
        4.12.1.  Compact: short strings
        4.12.2.  String Examples
    4.13.  type
    4.14.  Compact: type references
5.  Reference Maps
    5.1.  value reference
    5.2.  class reference
    5.3.  type reference
6.  Bytecode map


1. 介绍

Hessian是一种动态类型的二进制序列化和Web服务协议,专为面向对象的传输而设计。


2. 设计目标

Hessian是动态类型的,紧凑的,可跨语言移植。

Hessian协议具有以下设计目标:

  • 它必须自我描述序列化类型,即不需要外部模式或接口定义。

  • 必须与语言无关,包括支持脚本语言。

  • 必须一次性读取或写入。

  • 必须尽可能紧凑。

  • 必须简单,以便有效地测试和实施。

  • 必须尽可能快。

  • 它必须支持Unicode字符串。

  • 它必须支持8位二进制数据,而不必转义或使用附件。

  • 它必须支持加密,压缩,签名和事务上下文包络。


3. Hessian 语法

序列化语法

           # 开始
top        ::= value

           # 8-bit二进制数据,拆分成最大64k的chunks
           # 每个chunk最多表示4093个字符
binary     ::= x41 b1 b0 <binary-data> binary # 非末尾chunk,x41 b1 b0 是固定值,数据末尾加上binary作为结束
           ::= 'B' b1 b0 <binary-data>        # 末尾chunk,'B' b1 b0 是固定值
           ::= [x20-x2f] <binary-data>        # 长度为0-15的二进制binary数据
           ::= [x34-x37] <binary-data>        # 长度为0-1023的二进制binary数据

           # boolean true/false
boolean    ::= 'T'
           ::= 'F'

           # 对象的定义(紧凑地映射)
class-def  ::= 'C' string int string*

           # 自epoch(1970-01-01 00:00:00 UTC)以来的64bit毫秒编码的UTC时间
date       ::= x4a b7 b6 b5 b4 b3 b2 b1 b0
           ::= x4b b3 b2 b1 b0       # 自epoch(1970-01-01 00:00:00 UTC)开始的秒数

           # 64-bit IEEE double双精度类型
double     ::= 'D' b7 b6 b5 b4 b3 b2 b1 b0
           ::= x5b                   # 0.0
           ::= x5c                   # 1.0
           ::= x5d b0                # byte转化的double (-128.0 to 127.0)
           ::= x5e b1 b0             # short转化的double
           ::= x5f b3 b2 b1 b0       # 32-bit float转化的double

           # 32-bit 有符号整数
int        ::= 'I' b3 b2 b1 b0
           ::= [x80-xbf]             # -x10 to x3f
           ::= [xc0-xcf] b0          # -x800 to x7ff
           ::= [xd0-xd7] b1 b0       # -x40000 to x3ffff

           # list/vector
list       ::= x55 type value* 'Z'   # 可变长度的list
	   ::= 'V' type int value*   # 固定长度的ist
           ::= x57 value* 'Z'        # 可变长度的无类型list
           ::= x58 int value*        # 固定长度的无类型list
	   ::= [x70-77] type value*  # 固定长度的有类型list
	   ::= [x78-7f] value*       # 固定长度的无类型 list

           # 64-bit 有符号长整型
long       ::= 'L' b7 b6 b5 b4 b3 b2 b1 b0
           ::= [xd8-xef]             # -x08 到 x0f
           ::= [xf0-xff] b0          # -x800 到 x7ff
           ::= [x38-x3f] b1 b0       # -x40000 到 x3ffff
           ::= x59 b3 b2 b1 b0       # 32-bit 整型转化成长整型

           # map/object map或对象
map        ::= 'M' type (value value)* 'Z'  # key, value 映射键值对
	   ::= 'H' (value value)* 'Z'       # 无类型key, value键值对

           # null值
null       ::= 'N'

           # Object实例
object     ::= 'O' int value*
	   ::= [x60-x6f] value*

           # 值引用value reference (例如循环树和图表circular trees and graphs)
ref        ::= x51 int            # 引用第N个map/list/object

           # UTF-8 encoded character string split into 64k chunks
           # 被编码为utf-8的字符串,拆分到最大64k的chunks中
string     ::= x52 b1 b0 <utf8-data> string  # 非末尾 chunk
           ::= 'S' b1 b0 <utf8-data>         # 长度为0-65535的字符串
           ::= [x00-x1f] <utf8-data>         # 长度为0-31的字符串
           ::= [x30-x34] <utf8-data>         # 长度为0-1023的字符串

           # 用于面向对象语言的map/list类型
type       ::= string                        # type name
           ::= int                           # type reference

           # 值类型
value      ::= null
           ::= binary
           ::= boolean
           ::= class-def value
           ::= date
           ::= double
           ::= int
           ::= list
           ::= long
           ::= map
           ::= object
           ::= ref
           ::= string

4. Serialization

Hessian的对象序列化有8种原始类型:

  1. 原始二进制数据 binary

  2. boolean

  3. 64-bit 毫秒级 date

  4. 64-bit double

  5. 32-bit int

  6. 64-bit long

  7. null

  8. UTF8-encoded string

具有3种递归类型:

  1. list for lists and arrays

  2. map for maps and dictionaries

  3. object for objects

最后,还支持一种特殊构造:

  1. ref 用于共享和循环对象引用。

Hessian 2.0有3个内部 reference Map:


4.1. binary data 二进制数据

Binary 二进制语法

binary ::= b b1 b0 <binary-data> binary
       ::= B b1 b0 <binary-data>
       ::= [x20-x2f] <binary-data>

二进制数据会编码进chunks中。8位数值x42('B')用于编码末尾chunk,x62('b')则用于表示任一非末尾chunk。每个chunk具有16bit(2 byte)的长度值。

len = 256 * b1 + b0

  译者按:这里的x62('b')应该是错误的,因为从实际编码情况看,非末尾chunk实际是通过x41('A')来标识的,而末尾chunk确实用的是x42('B')。

4.1.1. 约定:短binary

长度小于等于15位的Binary数据可以使用8进制长度[x20-x2f]标识为更简单的格式。

len = code - 0x20


4.1.2. Binary示例

x20               # 0长度的Binary数据

x23 x01 x02 x03   # 3个byte数据

B x10 x00 ....    # 数据的最后4K的chunk

b x04 x00 ....    # 数据的非最后1k的Chunk

实际可以区分为4种编码方式:

A形
    # 长度[0, 15],可以代表字符数据的最后一个chunk。
    # 原始字符
    ssssssssss
    # 编码后
      0      1      2     3       4      5      6      7      8     9       10
    x2a(*) x73(s) x73(s) x73(s) x73(s) x73(s) x73(s) x73(s) x73(s) x73(s) x73(s)
B形
    # 长度[16, 1023],可以代表字符数据的最后一个chunk。
    # 原始字符B:8bit 25位长度字符串编码
    sssssssssssssssssssssssss
    # 编码后
    0  	1  	2  	3  	4  	5  	6  	7  	8  	9  	10 	11 	12 	13 	14 	15
    x34(4)	x19(NA)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)
    x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)
C形
    # 长度[1024, 4093], *不可以*代表字符数据的最后一个chunk,后面必须跟进A、B或D形编码才可作为编码结束的标识。
    # 原始字符C:(总长度1025位)
    sssssss....ssssss
    # 编码后
    0  	1  	2  	3  	4  	5  	6  	7  	8  	9  	10 	11 	12 	13 	14 	15
    x42(B)	x4(NA)	x1(NA)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)
    x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)
    ...
    x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)
    x73(s)	x73(s)	x73(s)	x73(s)
D形
    # 长度[1024, 4093], 可以代表字符数据的最后一个chunk,但通常不会独立出现,前面必须有C形编码才可出现。(因为A、B不满一个chunk,所以通常不会跟着A、B形一起出现)
    # 原始字符D1:(总计长度6144)(前256行属于C形编码,后129行属于D形编码)
    ssss....ssss
    # 编码后
    0  	1  	2  	3  	4  	5  	6  	7  	8  	9  	10 	11 	12 	13 	14 	15
    # 非最后一个chunk,以x41开头,后跟2位长度,后跟数据内容
    # 前256行如下,总计256 x 16个字符,其中包含 256 x 16 - 1 - 2 = x0FFD =  4093个实际数据字符
    x41(A)	x0f(NA)	xfd(NA)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)
    x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)
    ...
    x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)
    # 最后一个chunk,以x42开头,后跟2位长度,后跟数据内容
    # 后129行如下,总计128 x 16 + 6 = 2054个字符,其中包含 128 x 16 + 6 - 1 - 2 = x0FFD =  2051个实际数据字符
    x42(B)	x08(NA)	x03(NA)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)
    ...
    x73(s)	x73(s)	x73(s)	x73(s)	x73(s)	x73(s)

4.2.1. Boolean Examples

T   # true
F   # false

4.3. date

Date 语法

date ::= x4a b7 b6 b5 b4 b3 b2 b1 b0
     ::= x4b b4 b3 b2 b1 b0

Date 使用从1970年1月1日00:00,UTC开始的64bit长整型毫秒来表示。

4.3.1. 约定: 按分钟表示的date

第二种格式是从1970年1月1日00:00,UTC时间开始的,用32bit int来表示的分钟形式。

4.3.2. Date 示例

x4a x00 x00 x00 xd0 x4b x92 x84 xb8   # 09:51:31 May 8, 1998 UTC
x4b x4b x92 x0b xa0                 # 09:51:00 May 8, 1998 UTC

6. Hessian2的 Bytecode 速查表

Hessian通过bytecode协议进行组织。对于Hessian的读取器本质上就是读取8进制数据,选择解析状态,而后对后续文本进行解析。


4.4. double

Double Grammar

double ::= D b7 b6 b5 b4 b3 b2 b1 b0
       ::= x5b
       ::= x5c
       ::= x5d b0
       ::= x5e b1 b0
       ::= x5f b3 b2 b1 b0

A 64-bit IEEE floating pointer number. 64bit IEEE单精度数值。

4.4.1. 约定: double 0

double型的0.0可以用十六进制x5b表示。

4.4.2. 约定: double 1

double 1.0 可以使用十六进制x5c来表示。

4.4.3. 约定: double 8位字节

doubles 表示 -128.0 到 +127.0 之间的无小数点的数值时,可以使用两个从byte值转化而来的8位长度的字节来表示。

value = (double) b0

4.4.4. 约定: 短 double

doubles 表示 -32768.0 到 32767.0 之间的整数时,可以使用3个从short值转化而来的8位长度的字节来表示。

value = (double) (256 * b1 + b0)

4.4.5. 约定: double float

double 表示一个用4-octet来表示的32-bit float数值时,表示形式实际上和float是一样的。

4-octet(32bit)的double和float的语法实际上可以认为是一样的。


4.4.6. Double Examples

x5b          # 0.0
x5c          # 1.0

x5d x00      # 0.0
x5d x80      # -128.0
x5d x7f      # 127.0

x5e x00 x00  # 0.0
x5e x80 x00  # -32768.0
x5e x7f xff  # 32767.0

D x40 x28 x80 x00 x00 x00 x00 x00  # 12.25

4.5. int

Integer Grammar

int ::= 'I' b3 b2 b1 b0
    ::= [x80-xbf]
    ::= [xc0-xcf] b0
    ::= [xd0-xd7] b1 b0

32-bit有符号整数。整数可以使用以x49('I')开头,随后跟着4-octets(32-bit)的数值数据。数值数据使用big-endian方式表示。

value = (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;

  big-endia:微处理器将高位字节放在低地址单元中位元组由大到小字节序。

4.5.1. 约定: 1-octet integers

如果整数位于[-16, 47]区间内,那么可以使用在[x80, xbf]区间内的1-octet来表示。

value = code - 0x90 code = value + 0x90

4.5.2. 约定: 2-octet integers

如果整数位于[-2048, 2047]区间内,那么可以使用在[xc0, xcf]开头的2-octet来表示。(实际上写入数值时,该区间一般情况下无法包含[-16, 47]区间,因为一旦数值落入该区间,那么会自动降级为4.5.1的表示法。但读取数值时可以兼容)

value = ((code - 0xc8) << 8) + b0;

  译者按:按照官方给出的上述公式我目前也无法推导出正确的转化结果。如果有推导出来的同学希望不吝赐教。 但可以使用我整理的下列转化公式进行转化:
    # 其中xc000是[xc0, xcf]开头的高位octet + 低位补0
    hessian2IntValue = xc000 + x0800 + javaIntValue

    # 例如 -2045(-7FD)
    hessian2IntValue = xc000 + x0800 - x07fd = xc003

4.5.3. 约定: 3-octet integers

如果整数位于[-262144, 262143]区间内,那么可以使用在[xd0, xd7]开头的3-octet来表示。(实际上写入数值时,该区间一般情况下无法包含[-2048, 2047]区间,因为一旦数值落入该区间,那么会自动降级为4.5.1或4.5.2的表示法。但读取数值时可以兼容)

value = ((code - 0xd4) << 16) + (b1 << 8) + b0;

  译者按:类似于4.5.2,按照官方给出的上述公式我目前也无法推导出正确的转化结果。 但可以使用我整理的下列转化公式进行转化:
    # 其中xd00000是[xd0, xd7]开头的高位octet + 低位补0
    hessian2IntValue = xd00000 + x40000 + javaIntValue

    # 例如 262143(x3ffff)
    hessian2IntValue = xd00000 + x40000 + x3ffff = xd7ffff

4.5.4. Integer 示例

x90                # 0
x80                # -16
xbf                # 47

xc8 x00            # 0
xc0 x00            # -2048
xc7 x00            # -256
xcf xff            # 2047

xd4 x00 x00        # 0
xd0 x00 x00        # -262144
xd7 xff xff        # 262143

I x00 x00 x00 x00  # 0
I x00 x00 x01 x2c  # 300

4.6. list

List Grammar

list ::= x55 type value* 'Z'   # 可变长度 list
     ::= 'V' type int value*   # 固定长度 list
     ::= x57 value* 'Z'        # 可变长度 无类型 list
     ::= x58 int value*        # 固定长度 无类型 list
     ::= [x70-77] type value*  # 固定长度 有类型 list
     ::= [x78-7f] value*       # 固定长度 无类型 list

有序的list,比如数组。协议中分别有固定长度list和可变长度list,两种list都可以具有类型,类型字符串可以用任意utf-8字符串表示,但前提是服务双方需要能够理解该字符串。

每个list元素都可以被加入引用清单,以用于共享和循环使用。详情参考 ref element引用元素 。

任何解析器都必须能够接受null和ref类型的list。

不同的应用可以根据实际情况,确定在list中是否需要指定具体类型。例如,服务提供方可能是一种静态类型语言,并且向Hessian接口暴露了一些和数组相关的类型信息,但在客户端,数据被写入了一个动态类型语言,而该语言并不关心数组相关类型信息,因此可以创建一个通用的数组。


4.6.1. 约定: 定长 list

Hessian 2.0 允许以一种紧凑的方式指定list的长度,类型和长度都可以通过integers进行编码,前提是类型必须在之前已经被使用过。

4.6.2. List examples

序列化整型数组:int[] = {0, 1}

x56('V')             # 固定长度、类型的list
  x04 [int           # 编码int[]类型
  x92                # length = 2
  x90                # integer 0
  x91                # integer 1

无类型可变长list: list = {0, 1}

x57('W')             # 可变长,无类型
  x90                # integer 0
  x91                # integer 1
  Z

固定长度类型

x72                # 长度为2的有类型list
  x04 [int         # int[]类型(保存为第0号类型int)
  x90              # integer 0
  x91              # integer 1

x73                # 长度为3的有类型list
  x90              # 引用int[]类型(取第0号integer类型)
  x92              # integer 2
  x93              # integer 3
  x94              # integer 4

4.7. long

Long Grammar

long ::= L b7 b6 b5 b4 b3 b2 b1 b0
     ::= [xd8-xef]
     ::= [xf0-xff] b0
     ::= [x38-x3f] b1 b0
     ::= x4c b3 b2 b1 b0

64-bit 有符号整数。long型数据可以使用以1-octet x4c('L')开头,随后紧跟8-bytes big-endian编码的整数。


4.7.1. 约定: 1-octet longs

Longs 如果在 [-8, 15] 的区间内,那么可以使用[xd8, xef]区间的1-octet作为开头来表示数据。

value = (code - 0xe0)

example
    xd8 = -8
    xd9 = -7
    ......
    xef = 15

4.7.2. 约定: 2-octet longs

Longs 如果在 [-2048, 2047] 的区间内,那么可以使用[xf0, xff]开头的2-octet内容来表示数据。

value = ((code - 0xf8) << 8) + b0

example
    xf000 = -2048
    xf001 = -2047
    ......
    xffff = +2047

4.7.3. 约定: 3-octet longs

Longs 如果在 [-262144, 262143] 的区间内,那么可以使用[x38, x3f]开头的2-octet内容来表示数据。

value = ((code - 0x3c) << 16) + (b1 << 8) + b0

example
    x380000 = -262144
    x380001 = -262143
    ......
    x3fffff = +262143

4.7.4. 约定: 4-octet longs

Longs 如果适用于 32-bits 的编码区间,那么需要使用以x4c开头的5-octets数据来表示内容。

value = (b3 << 24) + (b2 << 16) + (b1 << 8) + b0


4.7.5. Long Examples


xe0                  # 0
xd8                  # -8
xef                  # 15

xf8 x00              # 0
xf0 x00              # -2048
xf7 x00              # -256
xff xff              # 2047

x3c x00 x00          # 0
x38 x00 x00          # -262144
x3f xff xff          # 262143

x4c x00 x00 x00 x00  # 0
x4c x00 x00 x01 x2c  # 300

L x00 x00 x00 x00 x00 x00 x01 x2c  # 300

4.8. map

Map Grammar

map        ::= M type (value value)* Z

Map的序列化模式同时也能够序列化Objects。类型元素用于描述map的类型。

类型字段也可以是空的(0长度的字符串)。如果没有指定类型,那么解析器可以自己选择类型。对于对象而言,无法识别的keys将被忽略。

每个map都会被添加到引用表中。无论何时,解析器在解析map的时候,必须能够兼容null或ref类型。

类型可以由service自己选择。


4.8.1. Map examples

一种稀疏数组。

map = new HashMap();
map.put(new Integer(1), "fee");
map.put(new Integer(16), "fie");
map.put(new Integer(256), "foe");

---

H           # untyped map (HashMap for Java)
  x91       # 1
  x03 fee   # "fee"

  xa0       # 16
  x03 fie   # "fie"

  xc9 x00   # 256
  x03 foe   # "foe"

  Z

Java对象的Map表示法

public class Car implements Serializable {
  String color = "aquamarine";
  String model = "Beetle";
  int mileage = 65536;
}
M
  x13 com.caucho.test.Car  # type

  x05 color                # color field
  x0a aquamarine

  x05 model                # model field
  x06 Beetle

  x07 mileage              # mileage field
  I x00 x01 x00 x00
  Z

4.9. null

Null Grammar

null ::= N

Null可以表示一个空(null)指针。

octet 'N' 可以表示一个 null 值。


4.10. object

Object 语法

class-def  ::= 'C' string int string*

object     ::= 'O' int value*
           ::= [x60-x6f] value*

4.10.1. 约定: class定义

Hessian 2.0 有一个约定,即对于同一个对象的同一个字段名只会序列化一次。

后续的对象只会序列化它们的值,而不需要再序列化字段名。

对象定义包括一个托管类型字符串、字段的数量和字段的名字。对象定义被保存到一个对象定义map中,然后可以通过一个整数来引用对象的实例。

4.10.2. 约定: 对象实例化

Hessian 2.0 有一个关于对象/类型的约定,即字段名只需要序列化一次。随后的对象只需要序列化它们的值。

对象实例可以基于前一个对象的定义来创建。然后通过整数来引用对象/类型的定义。


4.10.3. Object examples

Object serialization

class Car {
  String color;
  String model;
}

out.writeObject(new Car("red", "corvette"));
out.writeObject(new Car("green", "civic"));

---

C                        # object definition (#0)
  x0b example.Car        # type is example.Car
  x92                    # two fields
  x05 color              # color field name
  x05 model              # model field name

O                        # object def (long form)
  x90                    # object definition #0
  x03 red                # color field value
  x08 corvette           # model field value

x60                      # object def #0 (short form)
  x05 green              # color field value
  x05 civic              # model field value
enum Color {
  RED,
  GREEN,
  BLUE,
}

out.writeObject(Color.RED);
out.writeObject(Color.GREEN);
out.writeObject(Color.BLUE);
out.writeObject(Color.GREEN);
C                         # class definition #0
  x0b example.Color       # type is example.Color
  x91                     # one field
  x04 name                # enumeration field is "name"

x60                       # object #0 (class def #0)
  x03 RED                 # RED value

x60                       # object #1 (class def #0)
  x90                     # object definition ref #0
  x05 GREEN               # GREEN value

x60                       # object #2 (class def #0)
  x04 BLUE                # BLUE value

x51 x91                   # object ref #1, i.e. Color.GREEN

4.11. ref

Ref Grammar

ref ::= x51 int

在一次Hessian2序列化过程中,已经被list、map或者object实例化过的类型,可以通过一个整数数值来进行引用。对于每个从输入流读取的list、map或object,都在流中有一个整数型的标记,例如第一个list或map是'0',而第二个则是'1',等等等等。后续的引用可以使用前一个对象的位置。作为Writer也可以生成引用。而解析器必须能够识别它们。

引用能够关联到非完全读取的items。例如,循环链表将在整个链表被读取之前引用第一个链接。

可能的实现是在读取数组时将每个映射、列表和对象添加到数组中。ref将从数组中返回相应的值。为了支持循环结构,该实现将在填充内容之前立即存储映射、列表或对象。

每个映射或列表在解析时存储在数组中。ref选择一个存储的对象。第一个对象编号为“0”。


4.11.1. Ref Examples

循环list

list = new LinkedList();
list.data = 1;
list.tail = list;
C
  x0a LinkedList
  x92
  x04 head
  x04 tail

o x90      # object stores ref #0
  x91      # data = 1
  x51 x90  # next field refers to itself, i.e. ref #0

ref只引用列表、映射和对象元素。特别是字符串和二进制数据,只有在它们被包装在列表或映射中时才会共享引用。


4.12. string

String Grammar

string ::= x52 b1 b0 <utf8-data> string
       ::= S b1 b0 <utf8-data>
       ::= [x00-x1f] <utf8-data>
       ::= [x30-x33] b0 <utf8-data>

用UTF-8编码的16位unicode字符串。字符串以块的形式编码。x53 ('S')表示最终块,x52 ('R')表示任何非最终块。每个块都有一个16位无符号整数长度值。

长度是16位字符的数目,可能与字节数不同。

字符串块不能分割代理项对。

4.12.1. 约定: 短字符串

长度小于32的字符串可以用1-octet长度[x00-x1f]进行编码。

value = code


4.12.2. String Examples

x00                 # "", empty string
x05 hello           # "hello"
x01 xc3 x83         # "u00c3"

S x00 x05 hello     # "hello" in long form

x52 x00 x07 hello,  # "hello, world" split into two chunks
  x05 world

4.13. type

Type Grammar

type ::= string
     ::= int

映射或列表包含一个类型属性,该属性指示面向对象语言的映射或列表的类型名称。

每个类型都被添加到类型映射中以备将来参考。


4.14. 约定: type引用

重复类型字符串可以使用类型映射来引用以前使用的类型。类型引用是基于解析过程中遇到的所有类型的。


5. Reference Maps

Hessian 2.0 3个 reference maps:

  1. 一个 map/object/list reference map.

  2. 一个 class definition map.

  3. 一个 类型type (class name) map.

值引用映射允许Hessian支持任意图形,以及递归和循环数据结构。

类和类型映射通过避免重复公共字符串数据提高了Hessian效率。


5.1. 值引用

Hessian通过在字节码流中遇到列表、对象和映射来支持任意图形。

解析器必须将遇到的每个列表、对象和映射存储在引用映射中。

存储的对象可以与ref字节码一起使用。


5.2. class reference

每个对象定义都会自动添加到类映射中。解析器必须在遇到类映射时向其添加类定义。下面的对象实例将引用定义的类。


5.3. type reference

映射的类型字符串和列表值存储在类型映射中以供参考。

解析器必须在遇到类型映射时向其添加类型字符串。

6. Bytecode map

Hessian被组织成字节码协议。Hessian阅读器本质上是初始octet上的switch语句。

Bytecode Encoding

    x00 - x1f    # utf-8 string length 0-32
    x20 - x2f    # binary data length 0-16
    x30 - x33    # utf-8 string length 0-1023
    x34 - x37    # binary data length 0-1023
    x38 - x3f    # three-octet compact long (-x40000 to x3ffff)
    x40          # reserved (expansion/escape)
    x41          # 8-bit binary data non-final chunk ('A')
    x42          # 8-bit binary data final chunk ('B')
    x43          # object type definition ('C')
    x44          # 64-bit IEEE encoded double ('D')
    x45          # reserved
    x46          # boolean false ('F')
    x47          # reserved
    x48          # untyped map ('H')
    x49          # 32-bit signed integer ('I')
    x4a          # 64-bit UTC millisecond date
    x4b          # 32-bit UTC minute date
    x4c          # 64-bit signed long integer ('L')
    x4d          # map with type ('M')
    x4e          # null ('N')
    x4f          # object instance ('O')
    x50          # reserved
    x51          # reference to map/list/object - integer ('Q')
    x52          # utf-8 string non-final chunk ('R')
    x53          # utf-8 string final chunk ('S')
    x54          # boolean true ('T')
    x55          # variable-length list/vector ('U')
    x56          # fixed-length list/vector ('V')
    x57          # variable-length untyped list/vector ('W')
    x58          # fixed-length untyped list/vector ('X')
    x59          # long encoded as 32-bit int ('Y')
    x5a          # list/map terminator ('Z')
    x5b          # double 0.0
    x5c          # double 1.0
    x5d          # double represented as byte (-128.0 to 127.0)
    x5e          # double represented as short (-32768.0 to 327676.0)
    x5f          # double represented as float
    x60 - x6f    # object with direct type
    x70 - x77    # 定长list
    x78 - x7f    # 定长无类型list
    x80 - xbf    # one-octet compact int (-x10 to x3f, x90 is 0)
    xc0 - xcf    # two-octet compact int (-x800 to x7ff)
    xd0 - xd7    # three-octet compact int (-x40000 to x3ffff)
    xd8 - xef    # one-octet compact long (-x8 to xf, xe0 is 0)
    xf0 - xff    # two-octet compact long (-x800 to x7ff, xf8 is 0)
原文地址:https://www.cnblogs.com/prpl/p/10468654.html