JSON to Model, Model to JSON
use swift package manager add this git, Xcode will download swift-syntax package, then enable and trust Macro for first run.
Decoding Json values to Model properties via keyPaths. Swift Macro auto generates just a little keypathList function code, will not increase compile time too much.
define a struct
@JSONableMacro
struct Animal: JSONable {
var boolVal: Bool = false
var doubleVal: Double = 0
var intVal: Int = 0
var stringVal: String = ""
var dictVal: [String: Any] = [:]
var child4: OtherJSONableType?
}the @JSONableMacro generated code will be:
struct Animal: JSONable {
var boolVal: Bool = false
var doubleVal: Double = 0
var intVal: Int = 0
var stringVal: String = ""
var dictVal: [String: Any] = [:]
var child4: OtherJSONableType?
func allKeyPathList() -> [JSONableKeyPathObject] {
return [
.init(name: "boolVal", keyPath: \Animal.boolVal),
.init(name: "doubleVal", keyPath: \Animal.doubleVal),
.init(name: "intVal", keyPath: \Animal.intVal),
.init(name: "stringVal", keyPath: \Animal.stringVal),
.init(name: "dictVal", keyPath: \Animal.dictVal),
.init(name: "child4", keyPath: \Animal.child4),
]
}
}news:
- 新增宏
JSONableIngoreKey直接忽略属性的映射,包括encode和decode - 新增宏
JSONableCustomMapper替代customKeyPathList()方法
changes:
Date类型必须使用JSONableDateMapper或JSONableIngoreKey修饰- 移除
encodeJsonExcludedKeys实现,推荐使用JSONableIngoreKey - 移除
customKeyPathList()实现,推荐使用JSONableCustomMapper
news:
- 新增Date属性转化宏
JSONableDateMapper,以支持unix时间戳(秒和毫秒)
news:
- 新增自定义key宏
JSONableCustomKey,标记于属性前面
changes & fixed:
- 修复了连续定义的属性keyPathList代码生成缺少变量,例如
var a, b, c, d: String?
changes:
ValueTypeKeyPathProvider名称标记为废弃- macro实现去除
ExtensionMacro协议实现
news:
- 子类继承专用宏
JSONableSubclassMacro
changes:
- JSONable协议拆分为
KeyPathListProvider & JSONEncodeDecode - KeyPathListProvider将原有的
static var allKeyPathList改为func allKeyPathList() - JSONableKeyPathObject去除了泛型,keyPath需要补全Root类型,例如
\.name改为\XXX.name
issues:
- class继承时,混用父类keyPath和子类keyPath,导致
encodeJsonExcludedKeys无法正确排除
- 基础功能 JSONable + JSONableMacro宏
import MyJSONable
@JSONableMacro
struct Animal: JSONable {
var boolVal: Bool = false
var doubleVal: Double = 0
var intVal: Int = 0
var stringVal: String = ""
var child3: [String: Any] = [:]
}
var animal = Animal()
let json: [String: Any] = [
"boolVal": true,
"doubleVal": 3.14,
"intVal": 314,
"stringVal": "New Dog",
"child": [
"age2": 100,
"name2": "New Cow"
],
"child3": [
"age2": 22,
"name2": "New 222",
"stringList": [
"a", "b", "c",
],
],
]
animal.decodeFromJson(json: json)
let jsonString = animal.encodeToJsonString()use @JSONableMacro macro to auto generate allKeyPathList function, otherwise, write manually
must be final class
@JSONableMacro
final class ChildAnimal2: MyJSONable.JSONable {
var age2: Int = 0
var name2: String = ""
var stringList: [String]?
}if your superclass is JSONable, use macro JSONableSubclassMacro
@JSONableMacro
class Person: JSONable {
var boolVal: Bool?
var doubleVal: Double?
var intVal: Int?
var stringVal: String?
required init() {
}
}
@JSONableSubclassMacro
class Student: Person {
var name: String?
var id: Int = 0
}enum type from string or int
enum EnumStringAnimal: String, JSONableEnum {
case cat = "cat"
case dog = "dog"
}
enum EnumIntAnimal: Int, JSONableEnum {
case cat = 1
case dog = 2
}Different key from json
example using key "cccc" for property var children2
@JSONableCustomKey("cccc")
var children2: Child?
mapper JsonValue <--> ModelValue
write a JSONableMapper somewhere, like:
extension JSONableMapper where T == Int {
static let myFakeIntMapper = JSONableMapper<Int> { v in
return -100
} encode: { v in
return 100
}
}use macro JSONableCustomMapper on property and use this mapper for custom encode and decode. key is optional.
@JSONableMacro
struct Person5: JSONable {
var intVal: Int?
@JSONableCustomMapper("testCustom", mapper: .myFakeIntMapper)
var customMap: Int = 0
@JSONableCustomMapper(mapper: .myFakeIntMapper)
var customMap2: Int = 0
}example: i don't want the property price to be encoded or decoded, use new macro JSONableIgnoreKey
@JSONableMacro
struct Person4: JSONable {
var intVal: Int?
var stringVal: String?
@JSONableIgnoreKey
var ignoreVal: String = "abcde"
}
example: map unixTimeStamp to Date, key is optional.
@JSONableMacro
struct DateTest: JSONable {
@JSONableDateMapper("date1000", mapper: .unixTimeStampMilliSecond)
var date2: Date? // with custom key "date1000"
@JSONableDateMapper("date0", mapper: .unixTimeStampSecond)
var date: Date? // with custom key "date0"
@JSONableDateMapper(mapper: .unixTimeStampSecond)
var date3: Date? // with default key "date3" depends on name
}for other mapper, you can add extension to JSONableMapper where T == Date
extension JSONableMapper where T == Date {
public static let iso8601 = JSONableMapper<Date> { any in
// return your date
} encode: { date in
// return your value
}
}