/* * Copyright (c) 2025 SimcuTeam. All rights reserved. * ReflectionCache:字段元数据(含继承链、命名策略、@SerializerPropertyName/@SerializerIgnore)与缓存。 * * 已知限制(平台级): * - InstanceVariableInfo.getValue/setValue 有「声明类严格类型校验」,父类字段无法用子类实例读写, * 故 v1 仅枚举运行时类自身声明的 var 字段(父类字段暂不序列化)。 */ package simapi_serialization.common import std.collection.* import std.reflect.* /** * 单个字段的序列化元数据。 */ public class FieldMetadata { /// 反射字段名(如 _name) public var name: String = "" /// JSON 名称(@SerializerPropertyName 优先,否则按命名策略) public var jsonName: String = "" /// 是否忽略(@SerializerIgnore) public var ignore: Bool = false /// 字段类型 public var typeInfo: ?TypeInfo = None /// 字段读写句柄 public var variable: ?InstanceVariableInfo = None /// 是否可变(反序列化只写 var) public var mutable: Bool = false public init() {} } /** * 字段反射缓存:类 → 字段列表(首次反射,后续复用)。 */ public class ReflectionCache { private init() {} private static let _cache = HashMap>() /// 类型 → 是否有 @SerializerParent 宏生成的 exportJsonFields(Bool) private static let _exportCache = HashMap() /// 类型 → 是否有 @SerializerParent 宏生成的 importJsonFields(Bool) private static let _importCache = HashMap() /** * 该类型是否含 @SerializerParent 宏生成的导出静态方法(含缓存)。 */ public static func hasExportFields(typeInfo: ClassTypeInfo): Bool { hasParentMethod(typeInfo, "exportJsonFields", _exportCache) } /** * 该类型是否含 @SerializerParent 宏生成的导入静态方法(含缓存)。 */ public static func hasImportFields(typeInfo: ClassTypeInfo): Bool { hasParentMethod(typeInfo, "importJsonFields", _importCache) } private static func hasParentMethod(typeInfo: ClassTypeInfo, name: String, cache: HashMap): Bool { let key = typeInfo.qualifiedName if (let Some(cached) <- cache.get(key)) { return cached } let found = try { if (name == "exportJsonFields") { typeInfo.getStaticFunction(name, [typeInfo]) } else { typeInfo.getStaticFunction(name, [typeInfo, TypeInfo.of>()]) } true } catch (_: Exception) { false } cache[key] = found found } /** * 获取类型的字段元数据(含缓存)。 * @param typeInfo 目标类类型。 * @param namingPolicy 命名策略。 * @return 字段列表(仅该类自身声明的 var 字段)。 */ public static func getFields(typeInfo: ClassTypeInfo, namingPolicy: PropertyNamingPolicy): ArrayList { let key = typeInfo.qualifiedName if (let Some(cached) <- _cache.get(key)) { return cached } var fields = ArrayList() for (v in typeInfo.instanceVariables) { var meta = FieldMetadata() meta.name = v.name meta.variable = Some(v) meta.typeInfo = Some(v.typeInfo) meta.mutable = v.isMutable() // @SerializerIgnore if (v.findAnnotation().isSome()) { meta.ignore = true } // @SerializerPropertyName 优先 var jsonName = "" if (let Some(jsonProp) <- v.findAnnotation()) { jsonName = jsonProp.name } else { jsonName = applyNamingPolicy(v.name, namingPolicy) } meta.jsonName = jsonName fields.add(meta) } _cache[key] = fields fields } /** * 应用属性命名策略。 * 说明:不剥除字段名前导下划线——`_name` 原样输出 `_name`; * 策略只影响字母大小写(CamelCase 首字母小写、SnakeCase 大写转下划线)。 */ public static func applyNamingPolicy(fieldName: String, policy: PropertyNamingPolicy): String { match (policy) { case PropertyNamingPolicy.Keep => fieldName case PropertyNamingPolicy.CamelCase => toCamelCase(fieldName) case PropertyNamingPolicy.SnakeCase => toSnakeCase(fieldName) } } private static func toCamelCase(s: String): String { if (s.isEmpty()) { return s } let first = s[0..1].toAsciiLower() "${first}${s[1..]}" } private static func toSnakeCase(s: String): String { if (s.isEmpty()) { return s } var sb = StringBuilder() var first = true for (c in s.runes()) { let ch = UInt32(c) let isUpper = ch >= 0x41 && ch <= 0x5A if (isUpper) { if (!first) { sb.append("_") } sb.append(Rune(ch + 0x20)) } else { sb.append(c) } first = false } sb.toString() } }