1.6 Hprose 序列化
Hprose 提供了一套自己的序列化格式用来实现高效的跨语言跨平台的数据存储和交换。该序列化格式,在 hprose for javascript 中被实现为以下几个对象:
- hprose.Tags
- hprose.ClassManager
- hprose.BinaryString
- hprose.Writer
- hprose.Reader
- hprose.Formatter
其中 hprose.Tags
对象中包含了所有的 Hprose 序列化和 RPC 标记定义。Hprose 的使用者通常不需要关心该对象,因此这里不对该对象做详细介绍。
hprose.ClassManager
用于管理自定义类型与其它语言之间的映射关系。
hprose.BinaryString
用于包装二进制字符串。
hprose.Writer
用于进行细粒度的 Hprose 序列化操作。
hprose.Reader
用于进行细粒度的 Hprose 反序列化操作。
hprose.Formatter
用于进行粗粒度的 Hprose 序列化和反序列化操作。
另外,hprose
对象上也提供了三个帮助方法,用于注册自定义类型(register
),序列化(serialize
)和反序列化(unserialize
)数据。下面我们将对这几个对象和方法进行详细的介绍。
hprose.ClassManager
register 方法
hprose.ClassManager.register(class, alias);
在 javascript 中,是没有类的概念的,这里的类是指对象的构造器函数。
当 hprose 序列化对象时,需要知道对象的类名,但有时候,对象的构造器函数可能是个匿名函数,并没有函数名。或者我们在不同的语言中定义的类名可能不同,但结构相同或相近,我们希望这些定义不同的类的对象可以相互传递。那么就需要使用该方法来进行注册,注册成统一的别名之后,就可以相互传递了。
其中 class
表示要注册的类(对象的构造器函数),alias
表示注册的别名。例如:
var User = function() {
this.name = 'Tom';
this.age = 18;
}
hprose.ClassManager.register(User, 'User');
在有些语言中,类名是有名称空间(NameSpace)的,例如在 java 中,可能有这样一个类:my.package.User,我们希望它能跟这里的 User 进行交互,那我们应该这样做:
hprose.ClassManager.register(User, 'my_package_User');
注意上面的别名中,不是使用 .
做分隔符的,而是使用 _
,hprose 之所以这样做是因为有些语言不支持名称空间(NameSpace),还有些语言的名称空间(NameSpace)和类名之间不是使用 .
分隔符的,因此这里统一成 _
,这样既可以支持没有名称空间(NameSpace)的语言,也可以支持具有名称空间(NameSpace)的语言。
因为该方法比较常用,所以 hprose 还提供了一个简单的写法:
hprose.register(User, 'my_package_User');
getClassAlias 方法
hprose.ClassManager.getClassAlias(class);
通过类来查找别名,例如:
hprose.register(User, 'my_package_User');
console.log(hprose.ClassManager.getClassAlias(User));
输出结果为:
>
my_package_User
>
getClass 方法
hprose.ClassManager.getClass(alias);
通过别名来查找注册的类。例如:
var User = hprose.ClassManager.getClass('my_package_User');
hprose.BinaryString
构造器方法
var BinaryString = hprose.BinaryString;
var bs = new BinaryString(str);
将 str
包装成 BinaryString
对象,在序列化时,将按照二进制数据进行序列化。
binary 方法
该对象还有一个简化的构造方法:
var bs = hprose.binary(str);
该方法跟 BinaryString
构造器方法稍有区别,当使用构造器方法时,对 str
是否为二进制数据的有效性不进行检查,而使用 binary
方法则进行检查,如果不是二进制数据,则抛出异常。
hprose.Writer
构造器方法
var writer = new Writer(stream[, simple[, binary]]);
第一个参数 stream
是一个 StringIO
的实例对象,序列化数据将会写入到该对象中。
第二个参数 simple
如果为 true
,则不使用引用方式序列化,通常在序列化的数据中不包含引用类型数据时,设置为 true
可以加快速度。当包含引用类型数据时,需要设置为 false
(即默认值),尤其是当引用数据中包括递归数据时,如果不使用引用方式,会陷入死循环导致堆栈溢出的错误。
第三个参数 binary
为 true
时,数据序列化为二进制字符串,为 false
时,序列化为普通字符串。只有当序列化数据中包含二进制字符串数据时,才需要将该参数设置为 true
。序列化为二进制字符串的效率要低于序列化为普通字符串的效率。
stream 属性
只读属性,返回当前用于写入序列化数据的 StringIO
实例对象。该属性的值即上面构造器中的第一个参数。
binary 属性
可读写属性,表示该对象是否以二进制序列化,该属性的默认值即上面构造器的第三个参数。
serialize 方法
writer.serialize(value);
序列化数据 value
。其中 value
为任意 hprose 支持的类型。
writeInteger 方法
writer.writerInteger(value);
序列化一个整数 value
。其中 value
为一个 32 位有符号整型数。超过这个范围的整数按照长整型数格式序列化。
writeDouble 方法
writer.writeDouble(value);
序列化一个浮点数 value
。
writeBoolean 方法
writer.writeBoolean(value);
序列化一个布尔值 value
。
writeUTCDate 方法
writer.writeUTCDate(value);
序列化一个 UTC 日期时间值 value
。其中 value
为 Date
类型的实例对象。
writer.writeUTCDateWithRef(value);
序列化一个 UTC 日期时间值 value
,如果该值之前被序列化过,则作为引用序列化。
writeDate 方法
writer.writeDate(value);
序列化一个本地日期时间值 value
。其中 value
为 Date
类型的实例对象。
writer.writeDateWithRef(value);
序列化一个本地日期时间值 value
,如果该值之前被序列化过,则作为引用序列化。
writeTime 方法
writer.writeTime(value);
序列化一个本地时间值 value
。其中 value
为 Date
类型的实例对象。
writer.writeTimeWithRef(value);
序列化一个本地时间值 value
,如果该值之前被序列化过,则作为引用序列化。
writeBinary 方法
writer.writeBinary(value);
序列化一个二进制数据值 value
。其中 value
为 BinaryString
类型的实例对象或保存了二进制字符串的 String
类型的对象。只有当 binary
属性为 true
时,该方法才能调用,否则抛出异常。
writer.writeBinaryWithRef(value);
序列化一个二进制数据值 value
,如果该值之前被序列化过,则作为引用序列化。
writeString 方法
writer.writeString(value);
序列化一个字符串值 value
。
writer.writeStringWithRef(value);
序列化一个字符串值 value
,如果该值之前被序列化过,则作为引用序列化。
writeList 方法
writer.writeList(value);
序列化一个 List 值 value
。其中 value
是一个数组的实例对象。
writer.writeListWithRef(value);
序列化一个 List 值 value
,如果该值之前被序列化过,则作为引用序列化。
writeMap 方法
writer.writeMap(value);
序列化一个 Map 值 value
。其中 value
是一个普通的 javascript 对象(比如直接使用 JSON 形式创建的对象)或 ECMAScript 6 的 Map 对象。
writer.writeMapWithRef(value);
序列化一个 Map 值 value
,如果该值之前被序列化过,则作为引用序列化。
writeObject 方法
writer.writeObject(value);
序列化一个对象值 value
。其中 value
是一个对象。该对象的构造器已经通过 hprose.ClassManager.register
方法注册,或者该对象的构造器是一个非匿名函数。
writer.writeObjectWithRef(value);
序列化一个对象值 value
,如果该值之前被序列化过,则作为引用序列化。
reset 方法
writer.reset();
将序列化的引用计数器重置。
hprose.Reader
构造器方法
var reader = new Reader(stream[, simple[, useHarmonyMap[, binary]]]);
第一个参数 stream
是一个 StringIO
的实例对象,反序列化数据将会从该对象中读取。
第二个参数 simple
如果为 true
,则不使用引用方式反序列化,通常在反序列化的数据中不包含引用类型数据时,设置为 true
可以加快速度。当包含引用类型数据时,需要设置为 false
(即默认值),否则会抛出异常。
第三个参数 useHarmonyMap
如果为 true
,则反序列化 Map 时,会以 ECMAScript 6 中的 Map 类型的实例对象返回反序列化值。否则返回 Object 对象。当反序列化的 Map 的键(key)为非字符串以外的其它类型(或多种混合类型)时,将该参数设置为 true
可以得到更准确的反序列化结果。默认值为 false
。
第四个参数 binary
为 true
时,StringIO
的实例对象中的数据为二进制字符串,为 false
时,StringIO
的实例对象中的数据为普通字符串。只有当序列化数据中包含二进制字符串数据时,才需要将该参数设置为 true
。
stream 属性
只读属性,返回当前用于读取反序列化数据的 StringIO
实例对象。该属性的值即上面构造器中的第一个参数。
useHarmonyMap 属性
功能同上面的第三个参数一样,可以在对象创建之后进行设置。
binary 属性
功能同上面的第四个参数一样,可以在对象创建之后进行设置。
checkTag 方法
reader.checkTag(expectTag[, tag]);
如果第二个参数不存在,则自动读取当前流中的一个字符作为 tag
值。如果 expectTag
和 tag
不一致,则抛出异常。
该方法没有返回值。
checkTags 方法
reader.checkTags(expectTags[, tag]);
如果第二个参数不存在,则自动读取当前流中的一个字符作为 tag
值。如果 expectTags
中不包含 tag
,则抛出异常。
expectTags
是一个字符数组或者字符串,该数组或字符串中包含一个或多个 hprose.Tags 中的枚举值,但通常不会用其它取值。
如果该方法执行成功,返回 tag
值。
unserialize 方法
reader.unserialize();
从当前数据流中读取数据并返回反序列化结果。如果当前数据流中包含有多个序列化数据,则一次只返回一个结果。
如果反序列化过程中发生错误,则会抛出异常。
readInteger 方法
reader.readInteger();
从当前数据流中反序列化一个整数结果并返回。
如果反序列化过程中发生错误,则会抛出异常。
readLong 方法
reader.readLong();
从当前数据流中反序列化一个长整数结果并返回,如果该结果超出 JavaScript 可表示的整数范围,则以字符串形式返回结果。
如果反序列化过程中发生错误,则会抛出异常。
readDouble 方法
reader.readDouble();
从当前数据流中反序列化一个浮点数结果并返回。
如果反序列化过程中发生错误,则会抛出异常。
readBoolean 方法
reader.readBoolean();
从当前数据流中反序列化一个布尔值结果并返回。
如果反序列化过程中发生错误,则会抛出异常。
readDate 方法
reader.readDate();
从当前数据流中反序列化一个 Date 结果并返回。
如果反序列化过程中发生错误,则会抛出异常。
reader.readDateWithoutTag();
从当前数据流中反序列化一个 Date 结果并返回,该方法假设序列化标记已被读取,并且其值为 hprose.Tags.TagDate。
如果反序列化过程中发生错误,则会抛出异常。
readTime 方法
reader.readTime();
从当前数据流中反序列化一个只包含时间的 Date 结果并返回。
如果反序列化过程中发生错误,则会抛出异常。
reader.readTimeWithoutTag();
从当前数据流中反序列化一个只包含时间的 Date 结果并返回,该方法假设序列化标记已被读取,并且其值为 hprose.Tags.TagTime。
如果反序列化过程中发生错误,则会抛出异常。
readBinary 方法
reader.readBinary();
从当前数据流中反序列化一个二进制数据结果并返回。返回结果为 BinaryString
类型的实例对象。只有当 binary
属性为 true
时,该方法才能调用,否则抛出异常。
如果反序列化过程中发生错误,则会抛出异常。
reader.readBinaryWithoutTag();
从当前数据流中反序列化一个二进制数据结果并返回。该方法假设序列化标记已被读取,并且其值为 hprose.Tags.TagBytes。
如果反序列化过程中发生错误,则会抛出异常。
readString 方法
reader.readString();
从当前数据流中反序列化一个字符串结果并返回。
如果反序列化过程中发生错误,则会抛出异常。
reader.readStringWithoutTag();
从当前数据流中反序列化一个字符串结果并返回。该方法假设序列化标记已被读取,并且其值为 hprose.Tags.TagString。
如果反序列化过程中发生错误,则会抛出异常。
readGuid 方法
reader.readGuid();
从当前数据流中反序列化一个 GUID 结果并返回,结果为字符串类型。
如果反序列化过程中发生错误,则会抛出异常。
reader.readGuidWithoutTag();
从当前数据流中反序列化一个 GUID 结果并返回。该方法假设序列化标记已被读取,并且其值为 hprose.Tags.TagGuid。
如果反序列化过程中发生错误,则会抛出异常。
readList 方法
reader.readList();
从当前数据流中反序列化一个 List 结果并返回,结果为数组类型。
如果反序列化过程中发生错误,则会抛出异常。
reader.readListWithoutTag();
从当前数据流中反序列化一个 List 结果并返回。该方法假设序列化标记已被读取,并且其值为 hprose.Tags.TagList。
如果反序列化过程中发生错误,则会抛出异常。
readMap 方法
reader.readMap();
从当前数据流中反序列化一个 Map 结果并返回,结果为 Object 类型的实例对象或 ECMAScript 6 的 Map 类型的实例对象。
如果反序列化过程中发生错误,则会抛出异常。
reader.readMapWithoutTag();
从当前数据流中反序列化一个 Map 结果并返回。该方法假设序列化标记已被读取,并且其值为 hprose.Tags.TagMap。
如果反序列化过程中发生错误,则会抛出异常。
readObject 方法
reader.readObject();
从当前数据流中反序列化一个对象结果并返回。该对象的构造器会通过以下方式查找或生成:
如果已经通过 hprose.ClassManager.register
方法注册,并可以查找到,直接返回。
如果在全局通过遍历搜索可以查找到同名构造器,则自动注册,并返回。
通过将读取到的类名中的 _
分别替换成 .
来全局遍历查找同名构造器,如果找到,则自动注册,并返回。
如果通过以上方式都查找不到,则自动生成一个构造器,然后自动注册,并返回。
自动生成的构造器上会添加一个 getClassName 方法,该方法会返回反序列化时读取到的类名。
如果反序列化过程中发生错误,则会抛出异常。
reader.readObjectWithoutTag();
从当前数据流中反序列化一个对象结果并返回。该方法假设序列化标记已被读取,并且其值为 hprose.Tags.TagObject。
如果反序列化过程中发生错误,则会抛出异常。
reset 方法
reader.reset();
将反序列化的引用计数器重置。
hprose.Formatter
serialize 方法
hprose.Formatter.serialize(value[, simple[, binary]]);
该方法会将 value
进行序列化并返回序列化后的数据。如果 simple
为 true
,则不使用引用方式序列化,通常在序列化的数据 value
中不包含引用类型数据时,设置为 true
可以加快速度。当包含引用类型数据时,需要设置为 false
(即默认值),尤其是当引用数据中包括递归数据时,如果不使用引用方式,会陷入死循环导致堆栈溢出的错误。如果 value
中包含有二进制数据,则需要将 binary
参数设置为 true
,否则设置为 false
(即默认值)。
返回结果为 String
类型的对象实例。
如果序列化过程中发生错误,则会抛出异常。
hprose 还提供了一个简化写法:
hprose.serialize(value[, simple[, binary]]);
该简化写法跟完整写法在功能上没有任何区别。
unserialize 方法
hprose.Formatter.unserialize(stream[, simple[, useHarmonyMap[, binary]]]);
从数据流 stream
中读取数据并返回反序列化结果。如果当前数据流中包含有多个序列化数据,则一次只返回一个结果。
stream
为反序列化的数据来源,它可以是一个 StringIO
对象,也可以是一个字符串类型的对象。
第二个参数 simple
如果为 true
,则不使用引用方式反序列化,通常在反序列化的数据中不包含引用类型数据时,设置为 true
可以加快速度。当包含引用类型数据时,需要设置为 false
(即默认值),否则会抛出异常。
第三个参数 useHarmonyMap
如果为 true
,则反序列化 Map 时,会以 ECMAScript 6 中的 Map 类型的实例对象返回反序列化值。否则返回 Object 对象。当反序列化的 Map 的键(key)为非字符串以外的其它类型(或多种混合类型)时,将该参数设置为 true
可以得到更准确的反序列化结果。默认值为 false
。
第四个参数 binary
为 true
时,StringIO
的实例对象中的数据为二进制字符串,为 false
时,StringIO
的实例对象中的数据为普通字符串。只有当序列化数据中包含二进制字符串数据时,才需要将该参数设置为 true
。 如果反序列化过程中发生错误,则会抛出异常。
hprose 还提供了一个简化写法:
hprose.unserialize(stream[, simple[, useHarmonyMap[, binary]]]);
该简化写法跟完整写法在功能上没有任何区别。