You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

181 lines
8.1 KiB

/*
* Copyright 1999-2101 Alibaba Group.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Created by zhouzhuo on 7/7/16.
//
import Foundation
public extension HandyJSON {
/// Finds the internal dictionary in `dict` as the `designatedPath` specified, and converts it to a Model
/// `designatedPath` is a string like `result.data.orderInfo`, which each element split by `.` represents key of each layer
static func deserialize(from dict: NSDictionary?, designatedPath: String? = nil) -> Self? {
return deserialize(from: dict as? [String: Any], designatedPath: designatedPath)
}
/// Finds the internal dictionary in `dict` as the `designatedPath` specified, and converts it to a Model
/// `designatedPath` is a string like `result.data.orderInfo`, which each element split by `.` represents key of each layer
static func deserialize(from dict: [String: Any]?, designatedPath: String? = nil) -> Self? {
return JSONDeserializer<Self>.deserializeFrom(dict: dict, designatedPath: designatedPath)
}
/// Finds the internal JSON field in `json` as the `designatedPath` specified, and converts it to a Model
/// `designatedPath` is a string like `result.data.orderInfo`, which each element split by `.` represents key of each layer
static func deserialize(from json: String?, designatedPath: String? = nil) -> Self? {
return JSONDeserializer<Self>.deserializeFrom(json: json, designatedPath: designatedPath)
}
}
public extension Array where Element: HandyJSON {
/// if the JSON field finded by `designatedPath` in `json` is representing a array, such as `[{...}, {...}, {...}]`,
/// this method converts it to a Models array
static func deserialize(from json: String?, designatedPath: String? = nil) -> [Element?]? {
return JSONDeserializer<Element>.deserializeModelArrayFrom(json: json, designatedPath: designatedPath)
}
/// deserialize model array from NSArray
static func deserialize(from array: NSArray?) -> [Element?]? {
return JSONDeserializer<Element>.deserializeModelArrayFrom(array: array)
}
/// deserialize model array from array
static func deserialize(from array: [Any]?) -> [Element?]? {
return JSONDeserializer<Element>.deserializeModelArrayFrom(array: array)
}
}
public class JSONDeserializer<T: HandyJSON> {
/// Finds the internal dictionary in `dict` as the `designatedPath` specified, and map it to a Model
/// `designatedPath` is a string like `result.data.orderInfo`, which each element split by `.` represents key of each layer, or nil
public static func deserializeFrom(dict: NSDictionary?, designatedPath: String? = nil) -> T? {
return deserializeFrom(dict: dict as? [String: Any], designatedPath: designatedPath)
}
/// Finds the internal dictionary in `dict` as the `designatedPath` specified, and map it to a Model
/// `designatedPath` is a string like `result.data.orderInfo`, which each element split by `.` represents key of each layer, or nil
public static func deserializeFrom(dict: [String: Any]?, designatedPath: String? = nil) -> T? {
var targetDict = dict
if let path = designatedPath {
targetDict = getInnerObject(inside: targetDict, by: path) as? [String: Any]
}
if let _dict = targetDict {
return T._transform(dict: _dict) as? T
}
return nil
}
/// Finds the internal JSON field in `json` as the `designatedPath` specified, and converts it to Model
/// `designatedPath` is a string like `result.data.orderInfo`, which each element split by `.` represents key of each layer, or nil
public static func deserializeFrom(json: String?, designatedPath: String? = nil) -> T? {
guard let _json = json else {
return nil
}
do {
let jsonObject = try JSONSerialization.jsonObject(with: _json.data(using: String.Encoding.utf8)!, options: .allowFragments)
if let jsonDict = jsonObject as? NSDictionary {
return self.deserializeFrom(dict: jsonDict, designatedPath: designatedPath)
}
} catch let error {
InternalLogger.logError(error)
}
return nil
}
/// Finds the internal dictionary in `dict` as the `designatedPath` specified, and use it to reassign an exist model
/// `designatedPath` is a string like `result.data.orderInfo`, which each element split by `.` represents key of each layer, or nil
public static func update(object: inout T, from dict: [String: Any]?, designatedPath: String? = nil) {
var targetDict = dict
if let path = designatedPath {
targetDict = getInnerObject(inside: targetDict, by: path) as? [String: Any]
}
if let _dict = targetDict {
T._transform(dict: _dict, to: &object)
}
}
/// Finds the internal JSON field in `json` as the `designatedPath` specified, and use it to reassign an exist model
/// `designatedPath` is a string like `result.data.orderInfo`, which each element split by `.` represents key of each layer, or nil
public static func update(object: inout T, from json: String?, designatedPath: String? = nil) {
guard let _json = json else {
return
}
do {
let jsonObject = try JSONSerialization.jsonObject(with: _json.data(using: String.Encoding.utf8)!, options: .allowFragments)
if let jsonDict = jsonObject as? [String: Any] {
update(object: &object, from: jsonDict, designatedPath: designatedPath)
}
} catch let error {
InternalLogger.logError(error)
}
}
/// if the JSON field found by `designatedPath` in `json` is representing a array, such as `[{...}, {...}, {...}]`,
/// this method converts it to a Models array
public static func deserializeModelArrayFrom(json: String?, designatedPath: String? = nil) -> [T?]? {
guard let _json = json else {
return nil
}
do {
let jsonObject = try JSONSerialization.jsonObject(with: _json.data(using: String.Encoding.utf8)!, options: .allowFragments)
if let jsonArray = getInnerObject(inside: jsonObject, by: designatedPath) as? [Any] {
return jsonArray.map({ (item) -> T? in
return self.deserializeFrom(dict: item as? [String: Any])
})
}
} catch let error {
InternalLogger.logError(error)
}
return nil
}
/// mapping raw array to Models array
public static func deserializeModelArrayFrom(array: NSArray?) -> [T?]? {
return deserializeModelArrayFrom(array: array as? [Any])
}
/// mapping raw array to Models array
public static func deserializeModelArrayFrom(array: [Any]?) -> [T?]? {
guard let _arr = array else {
return nil
}
return _arr.map({ (item) -> T? in
return self.deserializeFrom(dict: item as? NSDictionary)
})
}
}
fileprivate func getInnerObject(inside object: Any?, by designatedPath: String?) -> Any? {
var result: Any? = object
var abort = false
if let paths = designatedPath?.components(separatedBy: "."), paths.count > 0 {
var next = object as? [String: Any]
paths.forEach({ (seg) in
if seg.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) == "" || abort {
return
}
if let _next = next?[seg] {
result = _next
next = _next as? [String: Any]
} else {
abort = true
}
})
}
return abort ? nil : result
}