Files
serialization-cj/README.md
T

222 lines
7.3 KiB
Markdown
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.
# serializationsimcu::serialization
SimApi 全反射 JSON 序列化库(仓颉版),对齐 .NET `System.Text.Json` 的用法与注解风格。
- **免标注**:任意类(无参构造 + `var` 字段)无需实现接口、无需标注,开箱即用
- **注解**`@SerializerPropertyName` / `@SerializerIgnore`(对齐 `[JsonPropertyName]` / `[JsonIgnore]`
- **继承支持**`@SerializerParent` 宏解决父类字段序列化(Cangjie 反射限制)
- **API 对齐**`JsonSerializer.Serialize(obj, JsonOption)` / `Deserialize<T>(json, JsonOption)`
- **字段名**`_` 前缀与无下划线字段均支持(`_name` 原样输出 `_name``name` 输出 `name`
## 快速开始
### 引入
两种方式任选其一:
**方式一:中央仓**(需先 `cjpm publish` 发布 `simcu::serialization`
```toml
[dependencies]
"simcu::serialization" = "1.0.3"
```
**方式二:Git 仓库**
```toml
[dependencies]
"simcu::serialization" = { git = "https://gitcode.com/simcu/serialization-cj.git", version = "1.0.3" }
```
> 本地开发也可用 path 依赖:`"simcu::serialization" = { path = "../simapi-serialization" }`
```cangjie
import simcu::serialization.* // 一个 import 全量可用(注解 + 序列化器)
```
### 序列化 / 反序列化
```cangjie
class User {
public var _name: String = ""
public var _age: Int64 = 0
public var active: Bool = true
public var _role: Role = Role.Member // 枚举 → 名字字符串
public var opt: ?String = None // OptionSome→值,None→null
public var _tags: Array<String> = []
public var addr: Address = Address() // 嵌套对象
}
let u = User()
u._name = "alice"
u._age = 30
let json = JsonSerializer.Serialize(u)
// { "_name": "alice", "_age": 30, "active": true, "_role": "Member", "opt": null, "_tags": [], "addr": {...} }
let u2 = JsonSerializer.Deserialize<User>(json)
// 全部字段回填
```
> 类无需显式 `public init() {}`——编译器自动提供无参构造(反射构造已验证)。
### 注解
```cangjie
class User {
@SerializerPropertyName["user_name"]
public var _username: String = "" // JSON 键用 user_name(对齐 [JsonPropertyName]
@SerializerIgnore
public var _temp: String = "" // 序列化/反序列化忽略(对齐 [JsonIgnore]
}
```
## 父类字段序列化(@SerializerParent
### 背景
Cangjie 反射对实例成员读写有**声明类严格校验**(`declaringClass != TypeInfo.of(instance)`),
父类字段无法用子类实例读写。`@SerializerParent` 宏在编译期生成静态导出/导入方法,
方法体内用静态类型访问字段,绕开该限制。
### 用法
```cangjie
import simcu::serialization.*
import simcu::serialization.macros.*
@SerializerParent // 标注在父类上;非 open 类自动补 open
class BaseUser {
public var _id: String = ""
public var _createdAt: String = ""
}
class User <: BaseUser { // 子类零改动
public var _name: String = ""
}
let u = User()
u._id = "u-1"
u._name = "alice"
let json = JsonSerializer.Serialize(u)
// 输出包含父类字段:{ "_name": "alice", "_id": "u-1", "_createdAt": "" }
```
> 宏支持**任意字段名**(`_` 前缀或无下划线均可),只需有类型注解。
### 特性
| 特性 | 说明 |
|---|---|
| 自动补 `open` | 非 open 类标注宏后自动可继承 |
| 多层继承 | 沿 `superClass` 链逐层调用;中间层无宏自动跳过 |
| 注解生效 | 父类字段的 `@SerializerPropertyName` / `@SerializerIgnore` 同样生效 |
| 任意字段名 | `_` 前缀与无下划线字段都处理 |
| 向后兼容 | 无宏的类行为不变 |
### 宏生成的方法
```cangjie
// 宏为父类自动生成(可直接调用):
BaseUser.exportJsonFields(instance) // HashMap<String, Any>
BaseUser.importJsonFields(instance, json) // 回填字段
```
## 选项(JsonOption
| 选项 | 默认 | 说明 |
|---|---|---|
| `propertyNamingPolicy` | `CamelCase` | 字段命名策略 |
| `enumAsString` | `true` | 枚举序列化为名字 |
| `maxDepth` | `64` | 递归深度上限(超过抛异常) |
```cangjie
let opt = JsonOption()
opt.propertyNamingPolicy = PropertyNamingPolicy.SnakeCase // userName → user_name
opt.maxDepth = 16
let json = JsonSerializer.Serialize(u, opt)
```
### 运行时类型反序列化(框架绑定用)
供框架模型绑定等场景按运行时类型反序列化(无需编译期泛型):
```cangjie
import std.reflect.*
let typeInfo = TypeInfo.of<MyDto>()
let obj: Any = JsonSerializer.Deserialize(typeInfo, jsonString)
```
### 命名策略(PropertyNamingPolicy
| 策略 | 效果 |
|---|---|
| `Keep` | 字段名原样(`_username``_username` |
| `CamelCase` | 首字母小写(`Name``name`;下划线字段保持原样) |
| `SnakeCase` | 大写转下划线(`userName``user_name` |
> 注:不剥除字段名前导下划线——`_name` 原样输出 `_name`。
## 支持的类型
| 类别 | 说明 |
|---|---|
| 基础类型 | `String` / `Bool` / 全部整数 / 浮点 / `Rune` |
| 集合 | `Array<T>` / `ArrayList<T>` / `HashSet<T>` |
| 字典 | `HashMap<K, V>`(键须可转字符串) |
| `Option<T>` | `Some(x)` → 值;`None``null` |
| 枚举 | 构造器名(`Role.Admin``"Admin"` |
| 普通类 | 无参构造 + `var` 字段;嵌套对象递归 |
### 宽松类型转换(反序列化)
JSON 数字 ↔ 字符串字段自动互转:`Deserialize<String>("42")``"42"`
`Deserialize<Int64>("\"42\"")``42`
## 已知限制
- 父类字段序列化需父类标注 `@SerializerParent`(见上文;Cangjie 反射平台限制)
- 反序列化要求目标类型**无参构造**(编译器自动提供,无需显式写 `init(){}`)、字段为 `var``let` 只读字段跳过)
- 集合/字典元素类型需为支持的类型
- 泛型父类暂不支持
## 包结构
```
src/
├── SimApiSerialization.cj // 根锚点:public import common.* + json.*
├── common/ // XML/JSON 共用
│ ├── Annotations.cj // @SerializerPropertyName / @SerializerIgnore
│ ├── ReflectionCache.cj // 字段元数据 + 继承链缓存
│ └── NamingPolicy.cj // PropertyNamingPolicy
├── json/ // JSON 序列化
│ ├── JsonSerializer.cj // 公开 API(含 TypeInfo 版 Deserialize
│ ├── JsonWriter.cj / JsonReader.cj
│ └── JsonOption.cj
├── macros/ // @SerializerParent 宏
│ └── SerializerParentMacro.cj
└── tests/ // 单元测试(独立子包)
└── JsonSerializer_test.cj // cjpm test18 用例
```
## 测试
```bash
cjpm test
# TOTAL: 18, PASSED: 18
```
覆盖:基础类型、对象字段输出、注解、Option、集合、HashMap、枚举、命名策略、
父类字段(宏)、多层继承、三级继承、maxDepth、宽松类型转换。
## 设计参考
- API 对齐 .NET `System.Text.Json``JsonSerializer.Serialize/Deserialize` + `JsonSerializerOptions`
- 注解对齐 `[JsonPropertyName]` / `[JsonIgnore]`
- 父类方案参考 soulsoft_serialization 的「宏生成静态类型字段代码」思路
(详见 `docs/父类字段序列化方案.md`