@endcrystal/jsonex
v0.5.1
Published
JSON扩展
Readme
@endcrystal/jsonex JSON扩展
与原生JSON的区别就是
JSONEx将类型信息一并序列化
这在模块化之前较易实现,只需保存类名,并在反序列化时访问这些全局的类即可
而在模块化之后则不能这样实现,因为不存在全局的类
JSONEx的本质就是将被@Serializable()修饰的类放到一个结构中存储起来,并在反序列化时在这个结构中读取而已
除此之外JSONEx还包含Map Set类型变量的序列化
灵感来源来自RPG Maker MZ中实现的JSONEx,但是在模块化之后失效
用前须知
请确保tsconfig.json中已开启以下项目:
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
}
}使用用例:
也可查看src/test/Json.test.ts
使用装饰器
可以使用装饰器使类可被类型序列化和反序列化
下面是一个使用用例:
测试类定义:
import {SuperClass} from "./SuperClass";
import {Serializable, Transient} from "../index";
import {SubClass1} from "./SubClass1";
import {SubClass2} from "./SubClass2";
import {TypeClass} from "./TypeClass";
// 必须使用序列化装饰器标记类,否则类将被反序列化为Object:
// 修饰器的参数没有任何作用,也可以不提供,参数只是为了提醒不要使用类型导入子类型
// 例如没有提供SubClass2
@Serializable(() => SuperClass, () => SubClass1, () => TypeClass)
export class RootClass {
num: number = 2;
// 被@Transient修饰的属性,不会被序列化
@Transient
str: string = "临时变量";
boolArr: boolean[] = [];
b: SuperClass = new SuperClass(2);
obj = {t: 1, t2: ""};
bObj: SuperClass = new SuperClass(3);
// 此时可能会使用类型导入导入TypeClass,这样的话会导致反序列化失败,可以使用@Serializable可选的参数提醒
typeClass: TypeClass | null = null;
// 即使是子类也可以被正常反序列化,请确保子类也被@Serializable修饰
c: SuperClass = new SubClass1(3);
d: SuperClass = new SubClass2(4);
bArr: SuperClass[] = [];
set: Set<SuperClass> = new Set<SuperClass>();
map: Map<string, SuperClass> = new Map<string, SuperClass>();
map2: Map<SuperClass, number> = new Map();
map3: Map<SuperClass, SuperClass> = new Map();
map4: Map<string, number> = new Map();
getNum(): number {
return this.num;
}
}import Serializable from "../Serializable";
import Transient from "../decorator/Transient";
@Serializable()
export class SuperClass {
@Transient
bool = true;
constructor(public n: number) {
}
getN() {
return this.n;
}
}import Serializable from "../Serializable";
import {SuperClass} from "./SuperClass";
import StringifyBefore from "../decorator/StringifyBefore";
import ParseAfter from "../decorator/ParseAfter";
@Serializable()
export class SubClass1 extends SuperClass {
message: string = "SubClass1";
// 被@StringifyBefore装饰的方法会在序列化之前运行
@StringifyBefore
stringifyBefore() {
this.message += "/stringifyBefore";
console.log("stringifyBefore");
}
// 被@ParseAfter装饰的方法会在反序列化之后运行
@ParseAfter
parseAfter() {
this.message += "/parseAfter";
console.log("parseAfter");
}
}import Serializable from "../Serializable";
import {SuperClass} from "./SuperClass";
@Serializable()
export class SubClass2 extends SuperClass {
message: string = "SubClass2";
}import Serializable from "../Serializable";
@Serializable()
export class TypeClass {
str = "TypeClass";
constructor(public n: number) {
}
getN() {
return this.n;
}
}序列化与反序列化:
import {JSONExImpl} from "../JSONExImpl";
import {RootClass} from "./RootClass";
import {SuperClass} from "./SuperClass";
import {SubClass1} from "./SubClass1";
import {SubClass2} from "./SubClass2";
import {TypeClass} from "./TypeClass";
it('json', function () {
let a = new RootClass();
a.num = 10;
a.bArr.push(new SuperClass(1));
a.bArr.push(new SuperClass(3));
a.bArr.push(new SubClass1(3));
a.bArr.push(new SubClass2(4));
a.boolArr.push(true);
a.boolArr.push(false);
a.set.add(new SuperClass(11));
a.set.add(new SuperClass(11));
a.set.add(new SuperClass(12));
a.set.add(new SubClass1(13));
a.map.set("21", new SuperClass(21));
a.map.set("22", new SuperClass(22));
a.map.set("sub1", new SubClass1(23));
a.map.set("sub2", new SubClass2(24));
a.map2.set(new SuperClass(23), 23);
a.map2.set(new SuperClass(23), 24);
a.map3.set(new SuperClass(25), new SuperClass(25));
a.map3.set(new SuperClass(26), new SuperClass(27));
a.map4.set("1", 1);
a.map4.set("2", 3);
a.typeClass = new TypeClass(6)
let s = JSONExImpl.stringify(a);
console.log(s);
let a1 = JSONExImpl.parse(s, RootClass);
expect(<unknown>a1 instanceof RootClass).toBeTruthy();
expect(<unknown>a1.b instanceof SuperClass).toBeTruthy();
expect(a1.c instanceof SubClass1).toBeTruthy();
expect(a1.d instanceof SubClass2).toBeTruthy();
expect(a1.bArr[0] instanceof SuperClass).toBeTruthy();
expect(a1.bArr[1] instanceof SuperClass).toBeTruthy();
expect(a1.bArr[2] instanceof SubClass1).toBeTruthy();
expect(a1.bArr[3] instanceof SubClass2).toBeTruthy();
expect(a1.map.get("21") instanceof SuperClass).toBeTruthy();
expect(a1.map.get("22") instanceof SuperClass).toBeTruthy();
expect(a1.map.get("sub1") instanceof SubClass1).toBeTruthy();
expect(a1.map.get("sub2") instanceof SubClass2).toBeTruthy();
expect(a1.typeClass instanceof TypeClass).toBeTruthy();
expect(a1.set instanceof Set).toBeTruthy();
expect(a1.set.size).eq(4);
debugger;
});直接注册
如果希望一些库的类支持类型序列化,可以使用直接调用装饰器的方法:
import Serializable from "../Serializable";
import LinkedList from "libName";
Serializable()(LinkedList);自定义序列化器
一些类因为特殊的机制无法自动的被带类型序列化
需要对其进行一些转换之后再进入序列化过程
例如Map和Set
此时可以注册自定义序列化器
已自动注册Map和Set的自定义序列化器
可参考其注册方法:
registerCustomSerializer({
constructor: Map,
replacer: map => Array.from(map.entries()),
reviver: json => new Map(json)
}
);
registerCustomSerializer({
constructor: Set,
replacer: before => Array.from(before.values()),
reviver: later => new Set(later)
});