Files
serialization-cj/src/json/JsonReader.cj
T
xrain e83bcaf68c 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> 类型不匹配异常
2026-08-17 12:11:35 +08:00

284 lines
12 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Copyright (c) 2025 SimcuTeam. All rights reserved.
* JsonReaderJsonValue → 对象(全反射)。
*
* - 目标类型来自泛型 TTypeInfo.of<T>()
* - 反序列化要求:无参构造 + var 字段(let 只读字段跳过)
* - 类型不匹配做宽松转换(JsonInt/JsonFloat/JsonString 互转)
*/
package simapi_serialization.json
import std.collection.*
import std.convert.*
import std.reflect.*
import stdx.encoding.json.*
/**
* 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: 反序列化结果类型不匹配")
}
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) {
// 必须用目标类型 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]
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([])
let fields = ReflectionCache.getFields(ct, options)
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 => ()
}
}
instance
}
/// 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()) {
case JsNull => None
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
}
}
// ===== 宽松类型转换 =====
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")
}
/// 生成某类型的占位默认值(用于构造 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}")
}
}