2026-08-17 10:47:46 +08:00
|
|
|
|
/*
|
|
|
|
|
|
* Copyright (c) 2025 SimcuTeam. All rights reserved.
|
|
|
|
|
|
* JsonReader:JsonValue → 对象(全反射)。
|
|
|
|
|
|
*
|
|
|
|
|
|
* - 目标类型来自泛型 T(TypeInfo.of<T>())
|
|
|
|
|
|
* - 反序列化要求:无参构造 + var 字段(let 只读字段跳过)
|
|
|
|
|
|
* - 类型不匹配做宽松转换(JsonInt/JsonFloat/JsonString 互转)
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
2026-08-18 04:26:31 +08:00
|
|
|
|
package simcu::serialization.json
|
2026-08-17 10:47:46 +08:00
|
|
|
|
|
|
|
|
|
|
import std.collection.*
|
|
|
|
|
|
import std.convert.*
|
|
|
|
|
|
import std.reflect.*
|
|
|
|
|
|
import stdx.encoding.json.*
|
2026-08-18 04:26:31 +08:00
|
|
|
|
import simcu::serialization.common.ReflectionCache
|
|
|
|
|
|
import simcu::serialization.common.FieldMetadata
|
2026-08-17 10:47:46 +08:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* JsonValue → 对象 读取器。
|
|
|
|
|
|
*/
|
|
|
|
|
|
public class JsonReader {
|
|
|
|
|
|
private init() {}
|
|
|
|
|
|
|
|
|
|
|
|
public static func read<T>(value: JsonValue, options: JsonOption): T {
|
|
|
|
|
|
let result = readValue(value, TypeInfo.of<T>(), options, 0)
|
|
|
|
|
|
if (let t: T <- result) {
|
|
|
|
|
|
return t
|
|
|
|
|
|
}
|
|
|
|
|
|
throw Exception("JsonSerializer: 反序列化结果类型不匹配")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-18 00:27:22 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 按运行时类型信息反序列化(供框架运行时绑定等场景使用,无需编译期泛型)。
|
|
|
|
|
|
* @param typeInfo 目标类型(运行时)。
|
|
|
|
|
|
* @param value JSON 值。
|
|
|
|
|
|
* @param options 序列化选项。
|
|
|
|
|
|
* @return 反序列化后的实例(Any)。
|
|
|
|
|
|
*/
|
|
|
|
|
|
public static func read(typeInfo: TypeInfo, value: JsonValue, options: JsonOption): Any {
|
|
|
|
|
|
readValue(value, typeInfo, options, 0)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-17 10:47:46 +08:00
|
|
|
|
private static func readValue(value: JsonValue, typeInfo: TypeInfo, options: JsonOption, depth: Int64): Any {
|
|
|
|
|
|
if (depth > options.maxDepth) {
|
|
|
|
|
|
throw Exception("JsonSerializer: 超过最大递归深度 ${options.maxDepth}")
|
|
|
|
|
|
}
|
|
|
|
|
|
let typeName = typeInfo.toString()
|
|
|
|
|
|
|
|
|
|
|
|
// 基本类型
|
|
|
|
|
|
match (typeName) {
|
|
|
|
|
|
case "String" => return readString(value)
|
|
|
|
|
|
case "Bool" => return readBool(value)
|
|
|
|
|
|
case "Int64" => return readInt64(value)
|
|
|
|
|
|
case "Int32" => return Int32(readInt64(value))
|
|
|
|
|
|
case "Int16" => return Int16(readInt64(value))
|
|
|
|
|
|
case "Int8" => return Int8(readInt64(value))
|
|
|
|
|
|
case "UInt8" => return UInt8(readInt64(value))
|
|
|
|
|
|
case "UInt16" => return UInt16(readInt64(value))
|
|
|
|
|
|
case "UInt32" => return UInt32(readInt64(value))
|
|
|
|
|
|
case "UInt64" => return UInt64(readInt64(value))
|
|
|
|
|
|
case "Float64" => return readFloat64(value)
|
|
|
|
|
|
case "Float32" => return Float32(readFloat64(value))
|
|
|
|
|
|
case "Rune" => return readChar(value)
|
|
|
|
|
|
case _ => ()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Option<X>:null → None;否则读取内层并用枚举构造器包 Some
|
|
|
|
|
|
if (typeName.startsWith("Option<")) {
|
|
|
|
|
|
if (value is JsonNull) {
|
2026-08-17 12:11:35 +08:00
|
|
|
|
// 必须用目标类型 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])
|
|
|
|
|
|
}
|
2026-08-17 14:06:13 +08:00
|
|
|
|
let noneVal: ?Any = None
|
|
|
|
|
|
return noneVal
|
2026-08-17 10:47:46 +08:00
|
|
|
|
}
|
|
|
|
|
|
let innerName = JsonWriter.extractTypeArgs(typeName)[0]
|
|
|
|
|
|
let innerVal = readValue(value, TypeInfo.get(innerName), options, depth + 1)
|
|
|
|
|
|
if (let et: EnumTypeInfo <- typeInfo) {
|
|
|
|
|
|
let ctor = et.getConstructor("Some", argsCount: 1)
|
|
|
|
|
|
return ctor.apply([innerVal])
|
|
|
|
|
|
}
|
|
|
|
|
|
return Some(innerVal)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 集合
|
|
|
|
|
|
if (typeName.startsWith("Array<")) {
|
|
|
|
|
|
let elemName = JsonWriter.extractTypeArgs(typeName)[0]
|
|
|
|
|
|
return readArray(value, elemName, options, depth)
|
|
|
|
|
|
}
|
|
|
|
|
|
if (typeName.startsWith("std.collection.ArrayList<")) {
|
|
|
|
|
|
let elemName = JsonWriter.extractTypeArgs(typeName)[0]
|
|
|
|
|
|
return readArrayList(value, elemName, options, depth)
|
|
|
|
|
|
}
|
|
|
|
|
|
if (typeName.startsWith("std.collection.HashSet<")) {
|
|
|
|
|
|
let elemName = JsonWriter.extractTypeArgs(typeName)[0]
|
|
|
|
|
|
return readHashSet(value, elemName, options, depth)
|
|
|
|
|
|
}
|
|
|
|
|
|
if (typeName.startsWith("std.collection.HashMap<")) {
|
|
|
|
|
|
let args = JsonWriter.extractTypeArgs(typeName)
|
|
|
|
|
|
return readHashMap(value, args[0], args[1], options, depth)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Any / Object → 通用读取
|
|
|
|
|
|
if (typeName == "Any" || typeName == "Object") {
|
|
|
|
|
|
return jsonToAny(value)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 枚举:按构造器名创建
|
|
|
|
|
|
if (let et: EnumTypeInfo <- typeInfo) {
|
|
|
|
|
|
let name = readString(value)
|
|
|
|
|
|
return et.construct(name, [])
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 对象:反射创建 + 赋值
|
|
|
|
|
|
if (let ct: ClassTypeInfo <- typeInfo) {
|
|
|
|
|
|
return readObject(value, ct, options, depth)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
throw Exception("JsonSerializer: 不支持的目标类型 ${typeName}")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static func readObject(value: JsonValue, ct: ClassTypeInfo, options: JsonOption, depth: Int64): Any {
|
|
|
|
|
|
let instance = ct.construct([])
|
2026-08-17 14:06:13 +08:00
|
|
|
|
let fields = ReflectionCache.getFields(ct, options.propertyNamingPolicy)
|
2026-08-17 10:47:46 +08:00
|
|
|
|
let jobj = value.asObject()
|
|
|
|
|
|
for (f in fields) {
|
|
|
|
|
|
if (f.ignore) {
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!f.mutable) {
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
|
|
|
|
|
match (jobj.get(f.jsonName)) {
|
|
|
|
|
|
case Some(jv) =>
|
|
|
|
|
|
if (jv is JsonNull) {
|
|
|
|
|
|
continue // null:跳过,保持字段默认值
|
|
|
|
|
|
}
|
|
|
|
|
|
let fieldVal = readValue(jv, f.typeInfo.getOrThrow(), options, depth + 1)
|
|
|
|
|
|
f.variable.getOrThrow().setValue(instance, fieldVal)
|
|
|
|
|
|
case None => ()
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-08-17 13:58:05 +08:00
|
|
|
|
// 父类字段(@SerializerParent 宏生成的静态导入方法,沿继承链逐层回填)
|
2026-08-17 14:19:44 +08:00
|
|
|
|
readParentFields(value, ct, instance)
|
2026-08-17 10:47:46 +08:00
|
|
|
|
instance
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-17 13:41:16 +08:00
|
|
|
|
/// 沿 superClass 链调用每层的 importJsonFields 静态方法回填父类字段。
|
|
|
|
|
|
/// 无宏的父类(hasImportFields 缓存判断)静默跳过;宏生成的方法内部按
|
|
|
|
|
|
/// if (k == "字段名") 忽略未知键,因此直接把全部 JSON 键传入即可。
|
2026-08-17 14:19:44 +08:00
|
|
|
|
private static func readParentFields(value: JsonValue, ct: ClassTypeInfo, instance: Any): Unit {
|
2026-08-17 13:41:16 +08:00
|
|
|
|
let jobj = value.asObject()
|
|
|
|
|
|
var parent = ct.superClass
|
|
|
|
|
|
while (let Some(p) <- parent) {
|
|
|
|
|
|
if (ReflectionCache.hasImportFields(p)) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
let fn = p.getStaticFunction("importJsonFields",
|
|
|
|
|
|
[p, TypeInfo.of<HashMap<String, Any>>()])
|
|
|
|
|
|
var pjson = HashMap<String, Any>()
|
|
|
|
|
|
for ((k, jv) in jobj.getFields()) {
|
|
|
|
|
|
if (!(jv is JsonNull)) {
|
|
|
|
|
|
pjson[k] = jsonToAny(jv)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
let args: Array<Any> = [instance, pjson]
|
|
|
|
|
|
fn.apply(p, args)
|
|
|
|
|
|
} catch (_: Exception) {
|
|
|
|
|
|
// 导入失败(如类型不匹配)不中断整体反序列化
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
parent = p.superClass
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-17 10:47:46 +08:00
|
|
|
|
/// Array<X>:经 ArrayList<X> 构造 + add + toArray
|
|
|
|
|
|
private static func readArray(value: JsonValue, elemName: String, options: JsonOption, depth: Int64): Any {
|
|
|
|
|
|
let listTypeName = "std.collection.ArrayList<${elemName}>"
|
|
|
|
|
|
let listCt = (TypeInfo.get(listTypeName) as ClassTypeInfo) ?? throw Exception("JsonSerializer: 无法解析类型 ${listTypeName}")
|
|
|
|
|
|
let list = listCt.construct([])
|
|
|
|
|
|
let addFunc = listCt.getInstanceFunction("add", [TypeInfo.get(elemName)])
|
|
|
|
|
|
let jarr = value.asArray()
|
|
|
|
|
|
for (item in jarr.getItems()) {
|
|
|
|
|
|
let elem = readValue(item, TypeInfo.get(elemName), options, depth + 1)
|
|
|
|
|
|
addFunc.apply(list, [elem])
|
|
|
|
|
|
}
|
|
|
|
|
|
let toArrayFunc = listCt.getInstanceFunction("toArray", [])
|
|
|
|
|
|
toArrayFunc.apply(list, [])
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static func readArrayList(value: JsonValue, elemName: String, options: JsonOption, depth: Int64): Any {
|
|
|
|
|
|
let ct = (TypeInfo.get("std.collection.ArrayList<${elemName}>") as ClassTypeInfo) ?? throw Exception("JsonSerializer: 无法解析 ArrayList<${elemName}>")
|
|
|
|
|
|
let list = ct.construct([])
|
|
|
|
|
|
let addFunc = ct.getInstanceFunction("add", [TypeInfo.get(elemName)])
|
|
|
|
|
|
let jarr = value.asArray()
|
|
|
|
|
|
for (item in jarr.getItems()) {
|
|
|
|
|
|
let elem = readValue(item, TypeInfo.get(elemName), options, depth + 1)
|
|
|
|
|
|
addFunc.apply(list, [elem])
|
|
|
|
|
|
}
|
|
|
|
|
|
list
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static func readHashSet(value: JsonValue, elemName: String, options: JsonOption, depth: Int64): Any {
|
|
|
|
|
|
let ct = (TypeInfo.get("std.collection.HashSet<${elemName}>") as ClassTypeInfo) ?? throw Exception("JsonSerializer: 无法解析 HashSet<${elemName}>")
|
|
|
|
|
|
let set = ct.construct([])
|
|
|
|
|
|
let addFunc = ct.getInstanceFunction("add", [TypeInfo.get(elemName)])
|
|
|
|
|
|
let jarr = value.asArray()
|
|
|
|
|
|
for (item in jarr.getItems()) {
|
|
|
|
|
|
let elem = readValue(item, TypeInfo.get(elemName), options, depth + 1)
|
|
|
|
|
|
addFunc.apply(set, [elem])
|
|
|
|
|
|
}
|
|
|
|
|
|
set
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static func readHashMap(value: JsonValue, keyName: String, valName: String, options: JsonOption,
|
|
|
|
|
|
depth: Int64): Any {
|
|
|
|
|
|
let ct = (TypeInfo.get("std.collection.HashMap<${keyName}, ${valName}>") as ClassTypeInfo) ?? throw Exception("JsonSerializer: 无法解析 HashMap<${keyName}, ${valName}>")
|
|
|
|
|
|
let map = ct.construct([])
|
|
|
|
|
|
let addFunc = ct.getInstanceFunction("add", [TypeInfo.get(keyName), TypeInfo.get(valName)])
|
|
|
|
|
|
let jobj = value.asObject()
|
|
|
|
|
|
for ((k, jv) in jobj.getFields()) {
|
|
|
|
|
|
let keyVal = readValue(JsonString(k), TypeInfo.get(keyName), options, depth + 1)
|
|
|
|
|
|
let valVal = readValue(jv, TypeInfo.get(valName), options, depth + 1)
|
|
|
|
|
|
addFunc.apply(map, [keyVal, valVal])
|
|
|
|
|
|
}
|
|
|
|
|
|
map
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// JsonValue → 通用 Any(动态结构)
|
|
|
|
|
|
private static func jsonToAny(v: JsonValue): Any {
|
|
|
|
|
|
match (v.kind()) {
|
2026-08-17 14:06:13 +08:00
|
|
|
|
case JsNull => noneAny()
|
2026-08-17 10:47:46 +08:00
|
|
|
|
case JsBool => v.asBool().getValue()
|
|
|
|
|
|
case JsInt => v.asInt().getValue()
|
|
|
|
|
|
case JsFloat => v.asFloat().getValue()
|
|
|
|
|
|
case JsString => v.asString().getValue()
|
|
|
|
|
|
case JsArray =>
|
|
|
|
|
|
var list = ArrayList<Any>()
|
|
|
|
|
|
for (item in v.asArray().getItems()) {
|
|
|
|
|
|
list.add(jsonToAny(item))
|
|
|
|
|
|
}
|
|
|
|
|
|
list.toArray()
|
|
|
|
|
|
case JsObject =>
|
|
|
|
|
|
var map = HashMap<String, Any>()
|
|
|
|
|
|
for ((k, val) in v.asObject().getFields()) {
|
|
|
|
|
|
map[k] = jsonToAny(val)
|
|
|
|
|
|
}
|
|
|
|
|
|
map
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-17 14:06:13 +08:00
|
|
|
|
private static func noneAny(): Any {
|
|
|
|
|
|
let noneVal: ?Any = None
|
|
|
|
|
|
noneVal
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-17 10:47:46 +08:00
|
|
|
|
// ===== 宽松类型转换 =====
|
|
|
|
|
|
|
|
|
|
|
|
private static func readString(v: JsonValue): String {
|
|
|
|
|
|
if (let s: JsonString <- v) { return s.getValue() }
|
|
|
|
|
|
if (let i: JsonInt <- v) { return "${i.getValue()}" }
|
|
|
|
|
|
if (let f: JsonFloat <- v) { return "${f.getValue()}" }
|
|
|
|
|
|
if (let b: JsonBool <- v) { return "${b.getValue()}" }
|
|
|
|
|
|
throw Exception("JsonSerializer: 无法转换为 String")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static func readInt64(v: JsonValue): Int64 {
|
|
|
|
|
|
if (let i: JsonInt <- v) { return i.getValue() }
|
|
|
|
|
|
if (let f: JsonFloat <- v) { return Int64(f.getValue()) }
|
|
|
|
|
|
if (let s: JsonString <- v) { return Int64.parse(s.getValue()) }
|
|
|
|
|
|
throw Exception("JsonSerializer: 无法转换为 Int64")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static func readFloat64(v: JsonValue): Float64 {
|
|
|
|
|
|
if (let f: JsonFloat <- v) { return f.getValue() }
|
|
|
|
|
|
if (let i: JsonInt <- v) { return Float64(i.getValue()) }
|
|
|
|
|
|
if (let s: JsonString <- v) { return Float64.parse(s.getValue()) }
|
|
|
|
|
|
throw Exception("JsonSerializer: 无法转换为 Float64")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static func readBool(v: JsonValue): Bool {
|
|
|
|
|
|
if (let b: JsonBool <- v) { return b.getValue() }
|
|
|
|
|
|
if (let s: JsonString <- v) { return s.getValue() == "true" }
|
|
|
|
|
|
throw Exception("JsonSerializer: 无法转换为 Bool")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static func readChar(v: JsonValue): Rune {
|
|
|
|
|
|
let s = readString(v)
|
|
|
|
|
|
for (r in s.runes()) {
|
|
|
|
|
|
return r
|
|
|
|
|
|
}
|
|
|
|
|
|
throw Exception("JsonSerializer: 无法转换为 Char")
|
|
|
|
|
|
}
|
2026-08-17 12:11:35 +08:00
|
|
|
|
|
|
|
|
|
|
/// 生成某类型的占位默认值(用于构造 Option<X> 的 None:None 的参数槽类型是 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}")
|
|
|
|
|
|
}
|
2026-08-17 10:47:46 +08:00
|
|
|
|
}
|