test: 新增 JsonSerializer 单元测试(cjpm test,13 用例);fix: 顶层 Deserialize<?T>(null) 返回类型化 None

- 覆盖:基础类型、对象字段输出(下划线保留/注解/忽略/None→null/继承限制)、
  Array/ArrayList/HashSet/HashMap 往返、枚举、命名策略、Option 字段、
  宽松类型转换、maxDepth
- 修复 JsonReader:Option 反序列化 null 时用反射构造目标类型 None 构造器
  (反射层 Option 构造器统一按 1 参数槽登记),而非返回裸 None 导致
  read<T> 类型不匹配异常
This commit is contained in:
2026-08-17 12:11:35 +08:00
parent 67da604294
commit e83bcaf68c
2 changed files with 329 additions and 0 deletions
+40
View File
@@ -55,6 +55,15 @@ public class JsonReader {
// Option<X>null → None;否则读取内层并用枚举构造器包 Some
if (typeName.startsWith("Option<")) {
if (value is JsonNull) {
// 必须用目标类型 Option<X> 的 None 构造器创建,保证运行时类型匹配。
// 反射层将 Option 构造器统一登记为 1 参数槽(None 的参数类型是内层 X),
// 传一个 X 的占位值即可(None 构造器忽略实参语义)。
if (let et: EnumTypeInfo <- typeInfo) {
let ctor = et.getConstructor("None", argsCount: 1)
let innerName = JsonWriter.extractTypeArgs(typeName)[0]
let placeholder = defaultValueFor(innerName)
return ctor.apply([placeholder])
}
return None
}
let innerName = JsonWriter.extractTypeArgs(typeName)[0]
@@ -240,4 +249,35 @@ public class JsonReader {
}
throw Exception("JsonSerializer: 无法转换为 Char")
}
/// 生成某类型的占位默认值(用于构造 Option<X> 的 NoneNone 的参数槽类型是 X)。
private static func defaultValueFor(typeName: String): Any {
match (typeName) {
case "String" => return ""
case "Bool" => return false
case "Int64" => return Int64(0)
case "Int32" => return Int32(0)
case "Int16" => return Int16(0)
case "Int8" => return Int8(0)
case "UInt64" => return UInt64(0)
case "UInt32" => return UInt32(0)
case "UInt16" => return UInt16(0)
case "UInt8" => return UInt8(0)
case "Float64" => return Float64(0.0)
case "Float32" => return Float32(0.0)
case "Rune" => return Rune(0)
case _ => ()
}
// 集合/对象/枚举:反射无参构造;失败则抛异常
if (let ct: ClassTypeInfo <- TypeInfo.get(typeName)) {
return ct.construct([])
}
if (let et: EnumTypeInfo <- TypeInfo.get(typeName)) {
// constructors 是 Collection:取第一个构造器名
let first = et.constructors.iterator().next().getOrThrow()
let ctor = et.getConstructor(first.name, argsCount: 0)
return ctor.apply([])
}
throw Exception("JsonSerializer: 无法为 Option 占位值构造类型 ${typeName}")
}
}