feat: 注解重命名(@PropertyName/@Ignore) + 新增 @NotRequired 默认必填语义, API 小写化 serialize/deserialize, 宏支持多注解组合, 版本号 1.2.0
This commit is contained in:
@@ -3,9 +3,10 @@
|
||||
SimApi 全反射 JSON 序列化库(仓颉版),对齐 .NET `System.Text.Json` 的用法与注解风格。
|
||||
|
||||
- **免标注**:任意类(无参构造 + `var` 字段)无需实现接口、无需标注,开箱即用
|
||||
- **注解**:`@SerializerPropertyName` / `@SerializerIgnore`(对齐 `[JsonPropertyName]` / `[JsonIgnore]`)
|
||||
- **注解**:`@PropertyName` / `@Ignore` / `@NotRequired`(对齐 `[JsonPropertyName]` / `[JsonIgnore]`,默认必填、`@NotRequired` 允许缺失)
|
||||
- **默认必填**:反序列化时要求每个 `var` 字段的键必须存在;标注 `@NotRequired` 的字段允许缺失(保持默认值)
|
||||
- **继承支持**:`@SerializerParent` 宏解决父类字段序列化(Cangjie 反射限制)
|
||||
- **API 对齐**:`JsonSerializer.Serialize(obj, JsonOption)` / `Deserialize<T>(json, JsonOption)`
|
||||
- **API 对齐**:`JsonSerializer.serialize(obj, JsonOption)` / `deserialize<T>(json, JsonOption)`
|
||||
- **字段名**:`_` 前缀与无下划线字段均支持(`_name` 原样输出 `_name`,`name` 输出 `name`)
|
||||
|
||||
## 快速开始
|
||||
@@ -18,14 +19,14 @@ SimApi 全反射 JSON 序列化库(仓颉版),对齐 .NET `System.Text.Jso
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
"simcu::serialization" = "1.0.3"
|
||||
"simcu::serialization" = "1.2.0"
|
||||
```
|
||||
|
||||
**方式二:Git 仓库**
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
"simcu::serialization" = { git = "https://gitcode.com/simcu/serialization-cj.git", version = "1.0.3" }
|
||||
"simcu::serialization" = { git = "https://gitcode.com/simcu/serialization-cj.git", version = "1.2.0" }
|
||||
```
|
||||
|
||||
> 本地开发也可用 path 依赖:`"simcu::serialization" = { path = "../simapi-serialization" }`
|
||||
@@ -51,10 +52,10 @@ let u = User()
|
||||
u._name = "alice"
|
||||
u._age = 30
|
||||
|
||||
let json = JsonSerializer.Serialize(u)
|
||||
let json = JsonSerializer.serialize(u)
|
||||
// { "_name": "alice", "_age": 30, "active": true, "_role": "Member", "opt": null, "_tags": [], "addr": {...} }
|
||||
|
||||
let u2 = JsonSerializer.Deserialize<User>(json)
|
||||
let u2 = JsonSerializer.deserialize<User>(json)
|
||||
// 全部字段回填
|
||||
```
|
||||
|
||||
@@ -64,14 +65,52 @@ let u2 = JsonSerializer.Deserialize<User>(json)
|
||||
|
||||
```cangjie
|
||||
class User {
|
||||
@SerializerPropertyName["user_name"]
|
||||
@PropertyName["user_name"]
|
||||
public var _username: String = "" // JSON 键用 user_name(对齐 [JsonPropertyName])
|
||||
|
||||
@SerializerIgnore
|
||||
@Ignore
|
||||
public var _temp: String = "" // 序列化/反序列化忽略(对齐 [JsonIgnore])
|
||||
|
||||
@NotRequired
|
||||
public var _nickname: String = "" // 反序列化时该键允许缺失(默认所有字段必填)
|
||||
|
||||
public var _id: String = "" // 默认必填:反序列化时键必须存在,否则抛异常
|
||||
}
|
||||
```
|
||||
|
||||
> 注解类构造器**必须写 `public const init() {}`**(`@Annotation` 强制 const 构造,`@Ignore`/`@NotRequired` 这类无参注解也不例外);缺省/非 const 都会编译报错。
|
||||
|
||||
#### @PropertyName
|
||||
|
||||
`字段名 → JSON 键名`,序列化与反序列化双向生效(对齐 `[JsonPropertyName]`)。
|
||||
|
||||
```cangjie
|
||||
@PropertyName["user_name"] public var _username: String = ""
|
||||
```
|
||||
|
||||
#### @Ignore
|
||||
|
||||
序列化/反序列化时跳过该字段(对齐 `[JsonIgnore]`)。
|
||||
|
||||
```cangjie
|
||||
@Ignore public var _temp: String = ""
|
||||
```
|
||||
|
||||
#### 默认必填 / @NotRequired
|
||||
|
||||
**默认所有 `var` 字段必填**:反序列化时要求 JSON 对象**必须包含每个 `var` 字段的键**,
|
||||
否则抛异常。值可为 `null`(`null` 保持字段默认值,不抛异常);只有**键缺失**才抛异常。
|
||||
仅对反序列化生效,序列化侧不受影响。
|
||||
|
||||
标注 `@NotRequired` 的字段允许键缺失(缺失时保持字段默认值,不抛异常):
|
||||
|
||||
```cangjie
|
||||
@NotRequired public var _nickname: String = ""
|
||||
```
|
||||
|
||||
- 普通类:`JsonSerializer.deserialize<T>(json)` 在 `readObject` 阶段检测,必填键缺失抛异常。
|
||||
- `@SerializerParent` 父类:宏生成的 `importJsonFields` 检测父类必填键,缺失抛异常并沿继承链上抛。
|
||||
|
||||
## 父类字段序列化(@SerializerParent)
|
||||
|
||||
### 背景
|
||||
@@ -100,7 +139,7 @@ let u = User()
|
||||
u._id = "u-1"
|
||||
u._name = "alice"
|
||||
|
||||
let json = JsonSerializer.Serialize(u)
|
||||
let json = JsonSerializer.serialize(u)
|
||||
// 输出包含父类字段:{ "_name": "alice", "_id": "u-1", "_createdAt": "" }
|
||||
```
|
||||
|
||||
@@ -112,7 +151,7 @@ let json = JsonSerializer.Serialize(u)
|
||||
|---|---|
|
||||
| 自动补 `open` | 非 open 类标注宏后自动可继承 |
|
||||
| 多层继承 | 沿 `superClass` 链逐层调用;中间层无宏自动跳过 |
|
||||
| 注解生效 | 父类字段的 `@SerializerPropertyName` / `@SerializerIgnore` 同样生效 |
|
||||
| 注解生效 | 父类字段的 `@PropertyName` / `@Ignore` / `@NotRequired` 同样生效 |
|
||||
| 任意字段名 | `_` 前缀与无下划线字段都处理 |
|
||||
| 向后兼容 | 无宏的类行为不变 |
|
||||
|
||||
@@ -137,7 +176,7 @@ let opt = JsonOption()
|
||||
opt.propertyNamingPolicy = PropertyNamingPolicy.SnakeCase // userName → user_name
|
||||
opt.maxDepth = 16
|
||||
|
||||
let json = JsonSerializer.Serialize(u, opt)
|
||||
let json = JsonSerializer.serialize(u, opt)
|
||||
```
|
||||
|
||||
### 运行时类型反序列化(框架绑定用)
|
||||
@@ -148,7 +187,7 @@ let json = JsonSerializer.Serialize(u, opt)
|
||||
import std.reflect.*
|
||||
|
||||
let typeInfo = TypeInfo.of<MyDto>()
|
||||
let obj: Any = JsonSerializer.Deserialize(typeInfo, jsonString)
|
||||
let obj: Any = JsonSerializer.deserialize(typeInfo, jsonString)
|
||||
```
|
||||
|
||||
### 命名策略(PropertyNamingPolicy)
|
||||
@@ -174,8 +213,8 @@ let obj: Any = JsonSerializer.Deserialize(typeInfo, jsonString)
|
||||
|
||||
### 宽松类型转换(反序列化)
|
||||
|
||||
JSON 数字 ↔ 字符串字段自动互转:`Deserialize<String>("42")` → `"42"`,
|
||||
`Deserialize<Int64>("\"42\"")` → `42`。
|
||||
JSON 数字 ↔ 字符串字段自动互转:`deserialize<String>("42")` → `"42"`,
|
||||
`deserialize<Int64>("\"42\"")` → `42`。
|
||||
|
||||
## 已知限制
|
||||
|
||||
@@ -190,24 +229,24 @@ JSON 数字 ↔ 字符串字段自动互转:`Deserialize<String>("42")` → `"
|
||||
src/
|
||||
├── SimApiSerialization.cj // 根锚点:public import common.* + json.*
|
||||
├── common/ // XML/JSON 共用
|
||||
│ ├── Annotations.cj // @SerializerPropertyName / @SerializerIgnore
|
||||
│ ├── Annotations.cj // @PropertyName / @Ignore / @NotRequired
|
||||
│ ├── ReflectionCache.cj // 字段元数据 + 继承链缓存
|
||||
│ └── NamingPolicy.cj // PropertyNamingPolicy
|
||||
├── json/ // JSON 序列化
|
||||
│ ├── JsonSerializer.cj // 公开 API(含 TypeInfo 版 Deserialize)
|
||||
│ ├── JsonSerializer.cj // 公开 API(含 TypeInfo 版 deserialize)
|
||||
│ ├── JsonWriter.cj / JsonReader.cj
|
||||
│ └── JsonOption.cj
|
||||
├── macros/ // @SerializerParent 宏
|
||||
│ └── SerializerParentMacro.cj
|
||||
└── tests/ // 单元测试(独立子包)
|
||||
└── JsonSerializer_test.cj // cjpm test,18 用例
|
||||
└── JsonSerializer_test.cj // cjpm test,21 用例
|
||||
```
|
||||
|
||||
## 测试
|
||||
|
||||
```bash
|
||||
cjpm test
|
||||
# TOTAL: 18, PASSED: 18
|
||||
# TOTAL: 21, PASSED: 21
|
||||
```
|
||||
|
||||
覆盖:基础类型、对象字段输出、注解、Option、集合、HashMap、枚举、命名策略、
|
||||
@@ -215,7 +254,7 @@ cjpm test
|
||||
|
||||
## 设计参考
|
||||
|
||||
- API 对齐 .NET `System.Text.Json`(`JsonSerializer.Serialize/Deserialize` + `JsonSerializerOptions`)
|
||||
- 注解对齐 `[JsonPropertyName]` / `[JsonIgnore]`
|
||||
- API 对齐 .NET `System.Text.Json`(`JsonSerializer.serialize/deserialize` + `JsonSerializerOptions`)
|
||||
- 注解对齐 `[JsonPropertyName]` / `[JsonIgnore]`;默认必填语义为库自身约定,`@NotRequired` 允许字段缺失
|
||||
- 父类方案参考 soulsoft_serialization 的「宏生成静态类型字段代码」思路
|
||||
(详见 `docs/父类字段序列化方案.md`)
|
||||
|
||||
Reference in New Issue
Block a user