序列化
Spire序列化(Serialization)是一个基于宏的自动序列化解决方案,通过简单的注解即可为类生成序列化和反序列化功能。它采用编译时代码生成的方式,提供高性能的序列化体验。
快速启动
只需要以下 3 个步骤即可开始使用序列化框架:
cangjie
import stdx.encoding.json.*
import spire_serialization.macros.*
import stdx.serialization.serialization.*
// 1. 使用@Serialization注解标记类
@Serialization
public class Student {
// 2. 定义以_开头的字段
private var _id: Int64 = 0
private var _name: ?String = None
private var _type: ?String = None
public static func create() {
return Student()
}
}
main() {
// 3.创建对象并使用序列化功能
let student = Student.create();
student.id = 123456
student.name = "cangjie"
// 序列化为Json
student.serialize().toJson() |> println
// 反序列化
let newStudent = Student.deserialize(DataModel.fromJson(student.serialize().toJson()))
println("姓名: ${newStudent.name}")
}说明
@Serialization 修饰的类如果没有实现无参构造方法,框架会自动实现一个私有无参构造方法,供反序列化使用
字段定义规范
字段命名规则
所有需要序列化的字段均以 “_” 开头才会被处理,并且需要序列化的字段必须声明为 var
cangjie
@Serialization
public class User {
// 不以_开头的字段会被忽略
private var userId: Int64 = 0 // 不会生成序列化代码
private var status: String = "" // 不会生成序列化代码
// 缺少类型标注会被忽略
private var _age = 0 // 不会生成序列化代码
// 不可变字段会被忽略
private let _address: String = String.empty // 不会生成序列化代码
// 非私有字段会被忽略
public var _gender: Int64 = 0
}属性覆盖
符合序列化规则的字段会自动生成属性,如果不需要,我们可以主动提供属性进行覆盖。 属性和字段的类型可以不一致,可以忽略setter
cangjie
public class Order {
private let _items: ArrayList<OrderItem> = ArrayList<OrderItem>()
// 使用同名属性覆盖
public prop items: ReadOnlyList<OrderItem> {
get() {
_items
}
}
}字段类型支持
框架支持多种数据类型的序列化:
cangjie
import stdx.encoding.json.*
import std.collection.*
import spire_serialization.macros.*
import stdx.serialization.serialization.*
// public class CantSerializable {} 没有实现序列化的类型
@Serialization
public class CantSerializable {}
@Serialization
public class DataTypes {
// 基础类型
private var _id: Int64 = 0
private var _name: String = ""
private var _price: Float64 = 0.0
private var _active: Bool = false
// 可选类型
private var _description: ?String = None
private var _categoryId: ?Int64 = None
// 集合类型(需要元素类型支持序列化)
private var _tags: Array<String> = []
private var _metadata: HashMap<String, String> = HashMap<String, String>()
// 实现序列化的类型
private var canSerializable: CantSerializable = CantSerializable()
// private var _cantserializable: CantSerializable = CantSerializable() // 不支持不可序列化的类型
}
main() {
let date = DataTypes()
date.serialize().toJson() |> println
}反序列化
从序列化数据重建对象:
cangjie
import stdx.encoding.json.*
import spire_serialization.macros.*
import stdx.serialization.serialization.*
@Serialization
class Order {
private var _orderId: Int64 = 0
private var _customerName: String = ""
private var _amount: Float64 = 0.0
}
main() {
let jsonData = """
{"orderId": 1001, "customerName": "Spire", "amount": 199.99}
"""
// 解析JSON为DataModel
let jsonValue = JsonValue.fromStr(jsonData)
let dataModel = DataModel.fromJson(jsonValue)
// 反序列化为对象
let order = Order.deserialize(dataModel)
println("Order ID: ${order.orderId} | "+"Customer: ${order.customerName} | "+"Amount: ${order.amount}")
}字段映射
如果json字段使用的是下划线,但是代码不希望它是下划线
cangjie
@Serialization
public class Order {
@DataField["user_name"]
private var _userName: String = String.empty
}字段注解支持
框架支持在字段上使用其他宏注解:
cangjie
@Serialization
public class Student {
@Column["student_id"]
@Description["学生唯一标识"]
private let _id: Int64 = 0
@Column["full_name"]
@Description["学生姓名"]
private var _name: String = ""
@Column["student_age"]
@Description["学生年龄"]
private var _age: ?Int64 = None
}注解兼容性
序列化宏能够正确处理字段上的其他宏注解,保持它们的功能不受影响
最佳实践
性能优化建议
- 避免反射:序列化代码在编译时生成,运行时无反射开销
- 类型安全:编译期类型检查,避免运行时类型错误
- 内联优化:生成的代码可被编译器进一步优化
- 避免深层嵌套:过深的对象嵌套可能影响序列化性能
架构设计
- 命名规范:所有需要序列化的类都必须使用
@Serialization注解 - 嵌套对象:嵌套对象的类型也必须支持序列化
- 字段命名规范:统一使用
_前缀命名需要序列化的字段
开发建议
- 合理使用可选类型:只在确实需要时使用
?类型 - 注解兼容性:序列化宏能够正确处理字段上的其他宏注解
- 类型支持:确保所有字段类型都支持序列化接口