feat: 实现 @JsonParent 宏——父类字段序列化/反序列化支持
- 新增 src/macros/JsonParentMacro.cj(macro package simapi_serialization.macros):
标注父类自动补 open,收集 public var 字段(跳过 @JsonIgnore,
@JsonPropertyName 用注解名),字符串拼接生成静态方法:
exportJsonFields(instance: T): HashMap<String, Any>
importJsonFields(instance: T, json: HashMap<String, Any>): Unit
- JsonWriter.writeParentFields:沿 superClass 链调用 exportJsonFields 合并父类字段
- JsonReader.readParentFields:沿 superClass 链调用 importJsonFields 回填父类字段
- ReflectionCache 增加 hasExportFields/hasImportFields 缓存(避免每次反射查找)
- 测试:16 用例全绿——新增 parentMacroMethods、multiLevelInheritance、
parentAutoOpen;更新 objectSerialize/objectRoundTrip 断言父类字段输出
This commit is contained in:
@@ -13,6 +13,7 @@ package simapi_serialization.json
|
||||
import std.collection.*
|
||||
import std.unittest.*
|
||||
import std.unittest.testmacro.*
|
||||
import simapi_serialization.macros.*
|
||||
|
||||
enum Role {
|
||||
| Admin
|
||||
@@ -26,10 +27,16 @@ class Address {
|
||||
public var zip: String = "" // 无下划线 → 原样输出 zip
|
||||
}
|
||||
|
||||
// 继承测试:父类字段(_id/_createdAt)受仓颉反射「声明类严格校验」限制
|
||||
// 继承测试:父类标注 @JsonParent 宏 → 自动补 open + 生成导出/导入静态方法,
|
||||
// 父类字段(_id/_createdAt)经宏的静态类型访问绕开反射声明类校验
|
||||
@JsonParent
|
||||
open class BaseUser {
|
||||
public var _id: String = ""
|
||||
public var _createdAt: String = ""
|
||||
@JsonIgnore
|
||||
public var _temp: String = ""
|
||||
@JsonPropertyName["parent_alias"]
|
||||
public var _parentAlias: String = ""
|
||||
}
|
||||
|
||||
class User <: BaseUser {
|
||||
@@ -48,8 +55,27 @@ class User <: BaseUser {
|
||||
public var temp: String = "secret" // 无下划线 + 忽略
|
||||
}
|
||||
|
||||
// 多层继承:爷(标宏)→ 父(不标宏)→ 子
|
||||
@JsonParent
|
||||
open class GrandParent {
|
||||
public var _gp: String = ""
|
||||
}
|
||||
|
||||
open class MidParent <: GrandParent {
|
||||
public var _mp: String = ""
|
||||
}
|
||||
|
||||
class LeafChild <: MidParent {
|
||||
public var _lc: String = ""
|
||||
public init() {}
|
||||
}
|
||||
|
||||
func makeUser(): User {
|
||||
let u = User()
|
||||
u._id = "u-1"
|
||||
u._createdAt = "2025-01-01"
|
||||
u._temp = "secret-parent"
|
||||
u._parentAlias = "parent-xiaoming"
|
||||
u._name = "alice"
|
||||
u._age = 30
|
||||
u.score = 88.5
|
||||
@@ -117,9 +143,14 @@ public class JsonSerializerTests {
|
||||
// 嵌套对象
|
||||
@Expect(json.contains("\"_city\": \"beijing\""), true)
|
||||
@Expect(json.contains("\"zip\": \"100000\""), true)
|
||||
// 继承限制:父类字段不序列化
|
||||
@Expect(json.contains("_id"), false)
|
||||
@Expect(json.contains("_createdAt"), false)
|
||||
// 父类字段(@JsonParent 宏):_id/_createdAt 输出,@JsonIgnore 父类字段不输出
|
||||
@Expect(json.contains("\"_id\": \"u-1\""), true)
|
||||
@Expect(json.contains("\"_createdAt\": \"2025-01-01\""), true)
|
||||
// 父类 @JsonPropertyName["parent_alias"] 生效
|
||||
@Expect(json.contains("\"parent_alias\": \"parent-xiaoming\""), true)
|
||||
@Expect(json.contains("_parentAlias"), false)
|
||||
// 父类 @JsonIgnore _temp 不输出
|
||||
@Expect(json.contains("secret-parent"), false)
|
||||
}
|
||||
|
||||
/// 对象反序列化往返
|
||||
@@ -135,6 +166,10 @@ public class JsonSerializerTests {
|
||||
@Expect(u2.addr.zip, "100000")
|
||||
@Expect(u2._alias, "xiaoming")
|
||||
@Expect(u2.temp, "secret") // @JsonIgnore:反序列化不改动默认值
|
||||
// 父类字段往返(@JsonParent 宏)
|
||||
@Expect(u2._id, "u-1")
|
||||
@Expect(u2._createdAt, "2025-01-01")
|
||||
@Expect(u2._parentAlias, "parent-xiaoming")
|
||||
// Option 往返
|
||||
let optVal: ?String = u2.opt
|
||||
@Expect(optVal.isSome(), true)
|
||||
@@ -286,4 +321,57 @@ public class JsonSerializerTests {
|
||||
}
|
||||
@Expect(threw, true)
|
||||
}
|
||||
|
||||
/// 父类字段序列化/反序列化(@JsonParent 宏):已并入 objectSerialize/objectRoundTrip,
|
||||
/// 此处验证宏生成的静态方法可直接调用
|
||||
@TestCase
|
||||
public func parentMacroMethods() {
|
||||
let u = User()
|
||||
u._id = "m-1"
|
||||
u._createdAt = "2025-02-02"
|
||||
u._parentAlias = "alias-m"
|
||||
// 宏生成的导出方法:子类实例作父类参数
|
||||
let m = BaseUser.exportJsonFields(u)
|
||||
@Expect(toStr(m["_id"]), "m-1")
|
||||
@Expect(toStr(m["_createdAt"]), "2025-02-02")
|
||||
@Expect(toStr(m["parent_alias"]), "alias-m")
|
||||
// @JsonIgnore 父类字段不导出
|
||||
@Expect(m.contains("_temp"), false)
|
||||
// 宏生成的导入方法
|
||||
var json = HashMap<String, Any>()
|
||||
json["_id"] = "m-2"
|
||||
json["parent_alias"] = "alias-m2"
|
||||
BaseUser.importJsonFields(u, json)
|
||||
@Expect(u._id, "m-2")
|
||||
@Expect(u._parentAlias, "alias-m2")
|
||||
@Expect(u._createdAt, "2025-02-02") // 未传的键保持原值
|
||||
}
|
||||
|
||||
/// 多层继承:爷标宏、中间层不标宏 → 爷字段导出,中间层字段不导出
|
||||
@TestCase
|
||||
public func multiLevelInheritance() {
|
||||
let leaf = LeafChild()
|
||||
leaf._gp = "gp-v"
|
||||
leaf._mp = "mp-v"
|
||||
leaf._lc = "lc-v"
|
||||
|
||||
let json = JsonSerializer.Serialize(leaf)
|
||||
@Expect(json.contains("\"_gp\": \"gp-v\""), true) // 爷字段(宏)导出
|
||||
@Expect(json.contains("_mp"), false) // 中间层无宏不导出
|
||||
@Expect(json.contains("\"_lc\": \"lc-v\""), true) // 子字段(反射)导出
|
||||
|
||||
let back = JsonSerializer.Deserialize<LeafChild>(json)
|
||||
@Expect(back._gp, "gp-v")
|
||||
@Expect(back._lc, "lc-v")
|
||||
@Expect(back._mp, "") // 中间层字段保持默认值
|
||||
}
|
||||
|
||||
/// 宏自动补 open:GrandParent 未显式写 open(@JsonParent 自动补),继承链可正常编译
|
||||
@TestCase
|
||||
public func parentAutoOpen() {
|
||||
let leaf = LeafChild()
|
||||
leaf._gp = "auto"
|
||||
let json = JsonSerializer.Serialize(leaf)
|
||||
@Expect(json.contains("\"_gp\": \"auto\""), true)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user