1.6 Hprose 序列化

优质
小牛编辑
127浏览
2023-12-01

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(即默认值),尤其是当引用数据中包括递归数据时,如果不使用引用方式,会陷入死循环导致堆栈溢出的错误。

第三个参数 binarytrue 时,数据序列化为二进制字符串,为 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。其中 valueDate 类型的实例对象。

writer.writeUTCDateWithRef(value);

序列化一个 UTC 日期时间值 value,如果该值之前被序列化过,则作为引用序列化。

writeDate 方法

writer.writeDate(value);

序列化一个本地日期时间值 value。其中 valueDate 类型的实例对象。

writer.writeDateWithRef(value);

序列化一个本地日期时间值 value,如果该值之前被序列化过,则作为引用序列化。

writeTime 方法

writer.writeTime(value);

序列化一个本地时间值 value。其中 valueDate 类型的实例对象。

writer.writeTimeWithRef(value);

序列化一个本地时间值 value,如果该值之前被序列化过,则作为引用序列化。

writeBinary 方法

writer.writeBinary(value);

序列化一个二进制数据值 value。其中 valueBinaryString 类型的实例对象或保存了二进制字符串的 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

第四个参数 binarytrue 时,StringIO 的实例对象中的数据为二进制字符串,为 false 时,StringIO 的实例对象中的数据为普通字符串。只有当序列化数据中包含二进制字符串数据时,才需要将该参数设置为 true

stream 属性

只读属性,返回当前用于读取反序列化数据的 StringIO 实例对象。该属性的值即上面构造器中的第一个参数。

useHarmonyMap 属性

功能同上面的第三个参数一样,可以在对象创建之后进行设置。

binary 属性

功能同上面的第四个参数一样,可以在对象创建之后进行设置。

checkTag 方法

reader.checkTag(expectTag[, tag]);

如果第二个参数不存在,则自动读取当前流中的一个字符作为 tag 值。如果 expectTagtag 不一致,则抛出异常。

该方法没有返回值。

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 进行序列化并返回序列化后的数据。如果 simpletrue,则不使用引用方式序列化,通常在序列化的数据 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

第四个参数 binarytrue 时,StringIO 的实例对象中的数据为二进制字符串,为 false 时,StringIO 的实例对象中的数据为普通字符串。只有当序列化数据中包含二进制字符串数据时,才需要将该参数设置为 true。 如果反序列化过程中发生错误,则会抛出异常。

hprose 还提供了一个简化写法:

hprose.unserialize(stream[, simple[, useHarmonyMap[, binary]]]);

该简化写法跟完整写法在功能上没有任何区别。