refactor: 新增 common 子包——XML/JSON 共用部分 + 单 import 全量可用
- src/common/(package simapi_serialization.common): Annotations.cj(@SerializerPropertyName/@SerializerIgnore)、 ReflectionCache.cj(字段元数据 + 继承链缓存)、NamingPolicy.cj(PropertyNamingPolicy) - 根锚点 public import common.* + json.*:import simapi_serialization.* 即可用全部 - JsonOption.propertyNamingPolicy 引用 common 枚举;getFields 改收命名策略 - 枚举值 PropertyNamingPolicy.None → Keep(None 与内置 Option.None 构造器同名冲突) - JsonWriter/JsonReader 单类 import common,避免循环依赖 - 测试/独立项目验证:16 用例全绿;serialization_test 单 import 即可运行
This commit is contained in:
@@ -1,12 +1,18 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2025 SimcuTeam. All rights reserved.
|
* Copyright (c) 2025 SimcuTeam. All rights reserved.
|
||||||
*
|
*
|
||||||
* simapi_serialization 根包锚点:注解类(@SerializerPropertyName / @SerializerIgnore)同包于此。
|
* simapi_serialization 根包锚点:聚合重导出,`import simapi_serialization.*`
|
||||||
* 序列化器位于子包 simapi_serialization.json(对应 .NET System.Text.Json)。
|
* 即可使用全部能力:
|
||||||
|
* - 注解(@SerializerPropertyName / @SerializerIgnore) → common 子包
|
||||||
|
* - 序列化器(JsonSerializer / JsonOption) → json 子包
|
||||||
*
|
*
|
||||||
* 用法:
|
* 子包结构:
|
||||||
* import simapi_serialization.* // 注解
|
* simapi_serialization.common XML/JSON 共用(注解、字段反射缓存、命名策略)
|
||||||
* import simapi_serialization.json.* // JsonSerializer / JsonOption
|
* simapi_serialization.json JSON 序列化
|
||||||
|
* simapi_serialization.macros @SerializerParent 宏
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package simapi_serialization
|
package simapi_serialization
|
||||||
|
|
||||||
|
public import simapi_serialization.common.*
|
||||||
|
public import simapi_serialization.json.*
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
* https://docs.cangjie-lang.cn/en/docs/1.0.0/libs/std/reflect/reflect_samples/annotation.html
|
* 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)。
|
* 指定字段的序列化名称(对齐 .NET JsonPropertyNameAttribute)。
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -7,11 +7,10 @@
|
|||||||
* 故 v1 仅枚举运行时类自身声明的 var 字段(父类字段暂不序列化)。
|
* 故 v1 仅枚举运行时类自身声明的 var 字段(父类字段暂不序列化)。
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package simapi_serialization.json
|
package simapi_serialization.common
|
||||||
|
|
||||||
import std.collection.*
|
import std.collection.*
|
||||||
import std.reflect.*
|
import std.reflect.*
|
||||||
import simapi_serialization.*
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 单个字段的序列化元数据。
|
* 单个字段的序列化元数据。
|
||||||
@@ -82,10 +81,10 @@ public class ReflectionCache {
|
|||||||
/**
|
/**
|
||||||
* 获取类型的字段元数据(含缓存)。
|
* 获取类型的字段元数据(含缓存)。
|
||||||
* @param typeInfo 目标类类型。
|
* @param typeInfo 目标类类型。
|
||||||
* @param options 序列化选项(命名策略)。
|
* @param namingPolicy 命名策略。
|
||||||
* @return 字段列表(仅该类自身声明的 var 字段)。
|
* @return 字段列表(仅该类自身声明的 var 字段)。
|
||||||
*/
|
*/
|
||||||
public static func getFields(typeInfo: ClassTypeInfo, options: JsonOption): ArrayList<FieldMetadata> {
|
public static func getFields(typeInfo: ClassTypeInfo, namingPolicy: PropertyNamingPolicy): ArrayList<FieldMetadata> {
|
||||||
let key = typeInfo.qualifiedName
|
let key = typeInfo.qualifiedName
|
||||||
if (let Some(cached) <- _cache.get(key)) {
|
if (let Some(cached) <- _cache.get(key)) {
|
||||||
return cached
|
return cached
|
||||||
@@ -106,7 +105,7 @@ public class ReflectionCache {
|
|||||||
if (let Some(jsonProp) <- v.findAnnotation<SerializerPropertyName>()) {
|
if (let Some(jsonProp) <- v.findAnnotation<SerializerPropertyName>()) {
|
||||||
jsonName = jsonProp.name
|
jsonName = jsonProp.name
|
||||||
} else {
|
} else {
|
||||||
jsonName = applyNamingPolicy(v.name, options.propertyNamingPolicy)
|
jsonName = applyNamingPolicy(v.name, namingPolicy)
|
||||||
}
|
}
|
||||||
meta.jsonName = jsonName
|
meta.jsonName = jsonName
|
||||||
fields.add(meta)
|
fields.add(meta)
|
||||||
@@ -122,7 +121,7 @@ public class ReflectionCache {
|
|||||||
*/
|
*/
|
||||||
public static func applyNamingPolicy(fieldName: String, policy: PropertyNamingPolicy): String {
|
public static func applyNamingPolicy(fieldName: String, policy: PropertyNamingPolicy): String {
|
||||||
match (policy) {
|
match (policy) {
|
||||||
case PropertyNamingPolicy.None => fieldName
|
case PropertyNamingPolicy.Keep => fieldName
|
||||||
case PropertyNamingPolicy.CamelCase => toCamelCase(fieldName)
|
case PropertyNamingPolicy.CamelCase => toCamelCase(fieldName)
|
||||||
case PropertyNamingPolicy.SnakeCase => toSnakeCase(fieldName)
|
case PropertyNamingPolicy.SnakeCase => toSnakeCase(fieldName)
|
||||||
}
|
}
|
||||||
+1
-11
@@ -5,17 +5,7 @@
|
|||||||
|
|
||||||
package simapi_serialization.json
|
package simapi_serialization.json
|
||||||
|
|
||||||
/**
|
import simapi_serialization.common.*
|
||||||
* 属性命名策略(对齐 .NET JsonNamingPolicy)。
|
|
||||||
*/
|
|
||||||
public enum PropertyNamingPolicy {
|
|
||||||
/// 字段名原样(_username → _username)
|
|
||||||
| None
|
|
||||||
/// 去前导下划线 + 首字母小写(_username → username,对齐 simapi/soulsoft 默认)
|
|
||||||
| CamelCase
|
|
||||||
/// 蛇形(userName → user_name,_username → username)
|
|
||||||
| SnakeCase
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 序列化选项。
|
* 序列化选项。
|
||||||
|
|||||||
+11
-3
@@ -13,6 +13,8 @@ import std.collection.*
|
|||||||
import std.convert.*
|
import std.convert.*
|
||||||
import std.reflect.*
|
import std.reflect.*
|
||||||
import stdx.encoding.json.*
|
import stdx.encoding.json.*
|
||||||
|
import simapi_serialization.common.ReflectionCache
|
||||||
|
import simapi_serialization.common.FieldMetadata
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JsonValue → 对象 读取器。
|
* JsonValue → 对象 读取器。
|
||||||
@@ -64,7 +66,8 @@ public class JsonReader {
|
|||||||
let placeholder = defaultValueFor(innerName)
|
let placeholder = defaultValueFor(innerName)
|
||||||
return ctor.apply([placeholder])
|
return ctor.apply([placeholder])
|
||||||
}
|
}
|
||||||
return None
|
let noneVal: ?Any = None
|
||||||
|
return noneVal
|
||||||
}
|
}
|
||||||
let innerName = JsonWriter.extractTypeArgs(typeName)[0]
|
let innerName = JsonWriter.extractTypeArgs(typeName)[0]
|
||||||
let innerVal = readValue(value, TypeInfo.get(innerName), options, depth + 1)
|
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 {
|
private static func readObject(value: JsonValue, ct: ClassTypeInfo, options: JsonOption, depth: Int64): Any {
|
||||||
let instance = ct.construct([])
|
let instance = ct.construct([])
|
||||||
let fields = ReflectionCache.getFields(ct, options)
|
let fields = ReflectionCache.getFields(ct, options.propertyNamingPolicy)
|
||||||
let jobj = value.asObject()
|
let jobj = value.asObject()
|
||||||
for (f in fields) {
|
for (f in fields) {
|
||||||
if (f.ignore) {
|
if (f.ignore) {
|
||||||
@@ -221,7 +224,7 @@ public class JsonReader {
|
|||||||
/// JsonValue → 通用 Any(动态结构)
|
/// JsonValue → 通用 Any(动态结构)
|
||||||
private static func jsonToAny(v: JsonValue): Any {
|
private static func jsonToAny(v: JsonValue): Any {
|
||||||
match (v.kind()) {
|
match (v.kind()) {
|
||||||
case JsNull => None
|
case JsNull => noneAny()
|
||||||
case JsBool => v.asBool().getValue()
|
case JsBool => v.asBool().getValue()
|
||||||
case JsInt => v.asInt().getValue()
|
case JsInt => v.asInt().getValue()
|
||||||
case JsFloat => v.asFloat().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 {
|
private static func readString(v: JsonValue): String {
|
||||||
|
|||||||
@@ -13,9 +13,11 @@ package simapi_serialization.json
|
|||||||
import std.collection.*
|
import std.collection.*
|
||||||
import std.unittest.*
|
import std.unittest.*
|
||||||
import std.unittest.testmacro.*
|
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.*
|
import simapi_serialization.macros.*
|
||||||
|
|
||||||
enum Role {
|
enum Role {
|
||||||
| Admin
|
| Admin
|
||||||
| User
|
| User
|
||||||
@@ -237,7 +239,7 @@ public class JsonSerializerTests {
|
|||||||
@TestCase
|
@TestCase
|
||||||
public func namingPolicies() {
|
public func namingPolicies() {
|
||||||
let optNone = JsonOption()
|
let optNone = JsonOption()
|
||||||
optNone.propertyNamingPolicy = PropertyNamingPolicy.None
|
optNone.propertyNamingPolicy = PropertyNamingPolicy.Keep
|
||||||
let jsonNone = JsonSerializer.Serialize(makeUser(), optNone)
|
let jsonNone = JsonSerializer.Serialize(makeUser(), optNone)
|
||||||
|
|
||||||
let optCamel = JsonOption()
|
let optCamel = JsonOption()
|
||||||
@@ -265,7 +267,7 @@ public class JsonSerializerTests {
|
|||||||
@Expect(ReflectionCache.applyNamingPolicy("Name", PropertyNamingPolicy.CamelCase), "name")
|
@Expect(ReflectionCache.applyNamingPolicy("Name", PropertyNamingPolicy.CamelCase), "name")
|
||||||
@Expect(ReflectionCache.applyNamingPolicy("_name", PropertyNamingPolicy.CamelCase), "_name")
|
@Expect(ReflectionCache.applyNamingPolicy("_name", PropertyNamingPolicy.CamelCase), "_name")
|
||||||
// None:原样
|
// None:原样
|
||||||
@Expect(ReflectionCache.applyNamingPolicy("Name", PropertyNamingPolicy.None), "Name")
|
@Expect(ReflectionCache.applyNamingPolicy("Name", PropertyNamingPolicy.Keep), "Name")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 枚举序列化/反序列化
|
/// 枚举序列化/反序列化
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ package simapi_serialization.json
|
|||||||
import std.collection.*
|
import std.collection.*
|
||||||
import std.reflect.*
|
import std.reflect.*
|
||||||
import stdx.encoding.json.*
|
import stdx.encoding.json.*
|
||||||
|
import simapi_serialization.common.ReflectionCache
|
||||||
|
import simapi_serialization.common.FieldMetadata
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 对象 → JsonValue 写入器。
|
* 对象 → JsonValue 写入器。
|
||||||
@@ -104,7 +106,7 @@ public class JsonWriter {
|
|||||||
private static func writeObject(value: Any, ct: ClassTypeInfo, options: JsonOption, depth: Int64): JsonValue {
|
private static func writeObject(value: Any, ct: ClassTypeInfo, options: JsonOption, depth: Int64): JsonValue {
|
||||||
let obj = JsonObject()
|
let obj = JsonObject()
|
||||||
// 1) 子类自身字段(反射)
|
// 1) 子类自身字段(反射)
|
||||||
let fields = ReflectionCache.getFields(ct, options)
|
let fields = ReflectionCache.getFields(ct, options.propertyNamingPolicy)
|
||||||
for (f in fields) {
|
for (f in fields) {
|
||||||
// 只要不是 @SerializerIgnore 的字段一律输出;None 字段输出 null
|
// 只要不是 @SerializerIgnore 的字段一律输出;None 字段输出 null
|
||||||
if (f.ignore) {
|
if (f.ignore) {
|
||||||
|
|||||||
Reference in New Issue
Block a user