diff --git a/src/SimApiSerialization.cj b/src/SimApiSerialization.cj index df1763d..72fb2a6 100644 --- a/src/SimApiSerialization.cj +++ b/src/SimApiSerialization.cj @@ -1,12 +1,18 @@ /* * Copyright (c) 2025 SimcuTeam. All rights reserved. * - * simapi_serialization 根包锚点:注解类(@SerializerPropertyName / @SerializerIgnore)同包于此。 - * 序列化器位于子包 simapi_serialization.json(对应 .NET System.Text.Json)。 + * simapi_serialization 根包锚点:聚合重导出,`import simapi_serialization.*` + * 即可使用全部能力: + * - 注解(@SerializerPropertyName / @SerializerIgnore) → common 子包 + * - 序列化器(JsonSerializer / JsonOption) → json 子包 * - * 用法: - * import simapi_serialization.* // 注解 - * import simapi_serialization.json.* // JsonSerializer / JsonOption + * 子包结构: + * simapi_serialization.common XML/JSON 共用(注解、字段反射缓存、命名策略) + * simapi_serialization.json JSON 序列化 + * simapi_serialization.macros @SerializerParent 宏 */ package simapi_serialization + +public import simapi_serialization.common.* +public import simapi_serialization.json.* diff --git a/src/Annotations.cj b/src/common/Annotations.cj similarity index 97% rename from src/Annotations.cj rename to src/common/Annotations.cj index c1d687f..2f7700d 100644 --- a/src/Annotations.cj +++ b/src/common/Annotations.cj @@ -12,7 +12,7 @@ * https://docs.cangjie-lang.cn/en/docs/1.0.0/libs/std/reflect/reflect_samples/annotation.html */ -package simapi_serialization +package simapi_serialization.common /** * 指定字段的序列化名称(对齐 .NET JsonPropertyNameAttribute)。 diff --git a/src/common/NamingPolicy.cj b/src/common/NamingPolicy.cj new file mode 100644 index 0000000..4b1fc3a --- /dev/null +++ b/src/common/NamingPolicy.cj @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 SimcuTeam. All rights reserved. + * NamingPolicy:字段命名策略(对齐 .NET JsonNamingPolicy)。 + * 供 JSON/XML 序列化器共用。 + */ + +package simapi_serialization.common + +/** + * 属性命名策略。 + * 注:原 None 枚举值因与内置 Option.None 构造器同名冲突,改名 Keep。 + */ +public enum PropertyNamingPolicy { + /// 字段名原样(_username → _username) + | Keep + /// 去前导下划线 + 首字母小写(_username → username,对齐 simapi/soulsoft 默认) + | CamelCase + /// 蛇形(userName → user_name,_username → username) + | SnakeCase +} diff --git a/src/json/ReflectionCache.cj b/src/common/ReflectionCache.cj similarity index 93% rename from src/json/ReflectionCache.cj rename to src/common/ReflectionCache.cj index 6b57550..2b95ed4 100644 --- a/src/json/ReflectionCache.cj +++ b/src/common/ReflectionCache.cj @@ -7,11 +7,10 @@ * 故 v1 仅枚举运行时类自身声明的 var 字段(父类字段暂不序列化)。 */ -package simapi_serialization.json +package simapi_serialization.common import std.collection.* import std.reflect.* -import simapi_serialization.* /** * 单个字段的序列化元数据。 @@ -82,10 +81,10 @@ public class ReflectionCache { /** * 获取类型的字段元数据(含缓存)。 * @param typeInfo 目标类类型。 - * @param options 序列化选项(命名策略)。 + * @param namingPolicy 命名策略。 * @return 字段列表(仅该类自身声明的 var 字段)。 */ - public static func getFields(typeInfo: ClassTypeInfo, options: JsonOption): ArrayList { + public static func getFields(typeInfo: ClassTypeInfo, namingPolicy: PropertyNamingPolicy): ArrayList { let key = typeInfo.qualifiedName if (let Some(cached) <- _cache.get(key)) { return cached @@ -106,7 +105,7 @@ public class ReflectionCache { if (let Some(jsonProp) <- v.findAnnotation()) { jsonName = jsonProp.name } else { - jsonName = applyNamingPolicy(v.name, options.propertyNamingPolicy) + jsonName = applyNamingPolicy(v.name, namingPolicy) } meta.jsonName = jsonName fields.add(meta) @@ -122,7 +121,7 @@ public class ReflectionCache { */ public static func applyNamingPolicy(fieldName: String, policy: PropertyNamingPolicy): String { match (policy) { - case PropertyNamingPolicy.None => fieldName + case PropertyNamingPolicy.Keep => fieldName case PropertyNamingPolicy.CamelCase => toCamelCase(fieldName) case PropertyNamingPolicy.SnakeCase => toSnakeCase(fieldName) } diff --git a/src/json/JsonOption.cj b/src/json/JsonOption.cj index d7eb61a..2c77df0 100644 --- a/src/json/JsonOption.cj +++ b/src/json/JsonOption.cj @@ -5,17 +5,7 @@ package simapi_serialization.json -/** - * 属性命名策略(对齐 .NET JsonNamingPolicy)。 - */ -public enum PropertyNamingPolicy { - /// 字段名原样(_username → _username) - | None - /// 去前导下划线 + 首字母小写(_username → username,对齐 simapi/soulsoft 默认) - | CamelCase - /// 蛇形(userName → user_name,_username → username) - | SnakeCase -} +import simapi_serialization.common.* /** * 序列化选项。 diff --git a/src/json/JsonReader.cj b/src/json/JsonReader.cj index 45ba25e..017178f 100644 --- a/src/json/JsonReader.cj +++ b/src/json/JsonReader.cj @@ -13,6 +13,8 @@ import std.collection.* import std.convert.* import std.reflect.* import stdx.encoding.json.* +import simapi_serialization.common.ReflectionCache +import simapi_serialization.common.FieldMetadata /** * JsonValue → 对象 读取器。 @@ -64,7 +66,8 @@ public class JsonReader { let placeholder = defaultValueFor(innerName) return ctor.apply([placeholder]) } - return None + let noneVal: ?Any = None + return noneVal } let innerName = JsonWriter.extractTypeArgs(typeName)[0] let innerVal = readValue(value, TypeInfo.get(innerName), options, depth + 1) @@ -114,7 +117,7 @@ public class JsonReader { private static func readObject(value: JsonValue, ct: ClassTypeInfo, options: JsonOption, depth: Int64): Any { let instance = ct.construct([]) - let fields = ReflectionCache.getFields(ct, options) + let fields = ReflectionCache.getFields(ct, options.propertyNamingPolicy) let jobj = value.asObject() for (f in fields) { if (f.ignore) { @@ -221,7 +224,7 @@ public class JsonReader { /// JsonValue → 通用 Any(动态结构) private static func jsonToAny(v: JsonValue): Any { match (v.kind()) { - case JsNull => None + case JsNull => noneAny() case JsBool => v.asBool().getValue() case JsInt => v.asInt().getValue() case JsFloat => v.asFloat().getValue() @@ -241,6 +244,11 @@ public class JsonReader { } } + private static func noneAny(): Any { + let noneVal: ?Any = None + noneVal + } + // ===== 宽松类型转换 ===== private static func readString(v: JsonValue): String { diff --git a/src/json/JsonSerializer_test.cj b/src/json/JsonSerializer_test.cj index bcecd50..f153e1f 100644 --- a/src/json/JsonSerializer_test.cj +++ b/src/json/JsonSerializer_test.cj @@ -13,9 +13,11 @@ package simapi_serialization.json import std.collection.* import std.unittest.* import std.unittest.testmacro.* -import simapi_serialization.* +import simapi_serialization.common.SerializerPropertyName +import simapi_serialization.common.SerializerIgnore +import simapi_serialization.common.PropertyNamingPolicy +import simapi_serialization.common.ReflectionCache import simapi_serialization.macros.* - enum Role { | Admin | User @@ -237,7 +239,7 @@ public class JsonSerializerTests { @TestCase public func namingPolicies() { let optNone = JsonOption() - optNone.propertyNamingPolicy = PropertyNamingPolicy.None + optNone.propertyNamingPolicy = PropertyNamingPolicy.Keep let jsonNone = JsonSerializer.Serialize(makeUser(), optNone) let optCamel = JsonOption() @@ -265,7 +267,7 @@ public class JsonSerializerTests { @Expect(ReflectionCache.applyNamingPolicy("Name", PropertyNamingPolicy.CamelCase), "name") @Expect(ReflectionCache.applyNamingPolicy("_name", PropertyNamingPolicy.CamelCase), "_name") // None:原样 - @Expect(ReflectionCache.applyNamingPolicy("Name", PropertyNamingPolicy.None), "Name") + @Expect(ReflectionCache.applyNamingPolicy("Name", PropertyNamingPolicy.Keep), "Name") } /// 枚举序列化/反序列化 diff --git a/src/json/JsonWriter.cj b/src/json/JsonWriter.cj index 7c518c9..a8b0098 100644 --- a/src/json/JsonWriter.cj +++ b/src/json/JsonWriter.cj @@ -11,6 +11,8 @@ package simapi_serialization.json import std.collection.* import std.reflect.* import stdx.encoding.json.* +import simapi_serialization.common.ReflectionCache +import simapi_serialization.common.FieldMetadata /** * 对象 → JsonValue 写入器。 @@ -104,7 +106,7 @@ public class JsonWriter { private static func writeObject(value: Any, ct: ClassTypeInfo, options: JsonOption, depth: Int64): JsonValue { let obj = JsonObject() // 1) 子类自身字段(反射) - let fields = ReflectionCache.getFields(ct, options) + let fields = ReflectionCache.getFields(ct, options.propertyNamingPolicy) for (f in fields) { // 只要不是 @SerializerIgnore 的字段一律输出;None 字段输出 null if (f.ignore) {