mirror of
https://github.com/OpenAPITools/openapi-generator.git
synced 2025-11-21 11:03:55 +00:00
* [Swift3] Add lenientTypeCast option
When set to true, this generates a client JSON decoder
that will accept and cast mistyped values.
Here:
- String => Bool ("true" instead of true),
- String => Int ("123" instead of 123),
- NSNumber => String (123 instead of "123").
The point is to allow the same client code to handle several
server implementations that may (sadly) not be up to spec,
or still be "evolving".
The conversion is not guaranteed if the input
Not a perfect/complete solution, not sure if it should be
activated along other casts, so kept behind an option.
* Update Petstore client code
252 lines
10 KiB
Plaintext
252 lines
10 KiB
Plaintext
// Models.swift
|
|
//
|
|
// Generated by swagger-codegen
|
|
// https://github.com/swagger-api/swagger-codegen
|
|
//
|
|
|
|
import Foundation
|
|
|
|
protocol JSONEncodable {
|
|
func encodeToJSON() -> Any
|
|
}
|
|
|
|
public enum ErrorResponse : Error {
|
|
case Error(Int, Data?, Error)
|
|
}
|
|
|
|
open class Response<T> {
|
|
open let statusCode: Int
|
|
open let header: [String: String]
|
|
open let body: T?
|
|
|
|
public init(statusCode: Int, header: [String: String], body: T?) {
|
|
self.statusCode = statusCode
|
|
self.header = header
|
|
self.body = body
|
|
}
|
|
|
|
public convenience init(response: HTTPURLResponse, body: T?) {
|
|
let rawHeader = response.allHeaderFields
|
|
var header = [String:String]()
|
|
for (key, value) in rawHeader {
|
|
header[key as! String] = value as? String
|
|
}
|
|
self.init(statusCode: response.statusCode, header: header, body: body)
|
|
}
|
|
}
|
|
|
|
private var once = Int()
|
|
class Decoders {
|
|
static fileprivate var decoders = Dictionary<String, ((AnyObject, AnyObject?) -> AnyObject)>()
|
|
|
|
static func addDecoder<T>(clazz: T.Type, decoder: @escaping ((AnyObject, AnyObject?) -> T)) {
|
|
let key = "\(T.self)"
|
|
decoders[key] = { decoder($0, $1) as AnyObject }
|
|
}
|
|
|
|
static func decode<T>(clazz: T.Type, discriminator: String, source: AnyObject) -> T {
|
|
let key = discriminator;
|
|
if let decoder = decoders[key] {
|
|
return decoder(source, nil) as! T
|
|
} else {
|
|
fatalError("Source \(source) is not convertible to type \(clazz): Maybe swagger file is insufficient")
|
|
}
|
|
}
|
|
|
|
static func decode<T>(clazz: [T].Type, source: AnyObject) -> [T] {
|
|
let array = source as! [AnyObject]
|
|
return array.map { Decoders.decode(clazz: T.self, source: $0, instance: nil) }
|
|
}
|
|
|
|
static func decode<T, Key: Hashable>(clazz: [Key:T].Type, source: AnyObject) -> [Key:T] {
|
|
let sourceDictionary = source as! [Key: AnyObject]
|
|
var dictionary = [Key:T]()
|
|
for (key, value) in sourceDictionary {
|
|
dictionary[key] = Decoders.decode(clazz: T.self, source: value, instance: nil)
|
|
}
|
|
return dictionary
|
|
}
|
|
|
|
static func decode<T>(clazz: T.Type, source: AnyObject, instance: AnyObject?) -> T {
|
|
initialize()
|
|
if T.self is Int32.Type && source is NSNumber {
|
|
return (source as! NSNumber).int32Value as! T
|
|
}
|
|
if T.self is Int64.Type && source is NSNumber {
|
|
return (source as! NSNumber).int64Value as! T
|
|
}
|
|
if T.self is UUID.Type && source is String {
|
|
return UUID(uuidString: source as! String) as! T
|
|
}
|
|
if source is T {
|
|
return source as! T
|
|
}
|
|
if T.self is Data.Type && source is String {
|
|
return Data(base64Encoded: source as! String) as! T
|
|
}
|
|
{{#lenientTypeCast}}
|
|
if T.self is Int32.Type && source is String {
|
|
return (source as! NSString).intValue as! T
|
|
}
|
|
if T.self is Int64.Type && source is String {
|
|
return (source as! NSString).intValue as! T
|
|
}
|
|
if T.self is Bool.Type && source is String {
|
|
return (source as! NSString).boolValue as! T
|
|
}
|
|
if T.self is String.Type && source is NSNumber {
|
|
return String(describing: source) as! T
|
|
}
|
|
{{/lenientTypeCast}}
|
|
|
|
let key = "\(T.self)"
|
|
if let decoder = decoders[key] {
|
|
return decoder(source, instance) as! T
|
|
} else {
|
|
fatalError("Source \(source) is not convertible to type \(clazz): Maybe swagger file is insufficient")
|
|
}
|
|
}
|
|
|
|
static func decodeOptional<T>(clazz: T.Type, source: AnyObject?) -> T? {
|
|
if source is NSNull {
|
|
return nil
|
|
}
|
|
return source.map { (source: AnyObject) -> T in
|
|
Decoders.decode(clazz: clazz, source: source, instance: nil)
|
|
}
|
|
}
|
|
|
|
static func decodeOptional<T>(clazz: [T].Type, source: AnyObject?) -> [T]? {
|
|
if source is NSNull {
|
|
return nil
|
|
}
|
|
return source.map { (someSource: AnyObject) -> [T] in
|
|
Decoders.decode(clazz: clazz, source: someSource)
|
|
}
|
|
}
|
|
|
|
static func decodeOptional<T, Key: Hashable>(clazz: [Key:T].Type, source: AnyObject?) -> [Key:T]? {
|
|
if source is NSNull {
|
|
return nil
|
|
}
|
|
return source.map { (someSource: AnyObject) -> [Key:T] in
|
|
Decoders.decode(clazz: clazz, source: someSource)
|
|
}
|
|
}
|
|
|
|
private static var __once: () = {
|
|
let formatters = [
|
|
"yyyy-MM-dd",
|
|
"yyyy-MM-dd'T'HH:mm:ssZZZZZ",
|
|
"yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ",
|
|
"yyyy-MM-dd'T'HH:mm:ss'Z'",
|
|
"yyyy-MM-dd'T'HH:mm:ss.SSS",
|
|
"yyyy-MM-dd HH:mm:ss"
|
|
].map { (format: String) -> DateFormatter in
|
|
let formatter = DateFormatter()
|
|
formatter.dateFormat = format
|
|
return formatter
|
|
}
|
|
// Decoder for Date
|
|
Decoders.addDecoder(clazz: Date.self) { (source: AnyObject, instance: AnyObject?) -> Date in
|
|
if let sourceString = source as? String {
|
|
for formatter in formatters {
|
|
if let date = formatter.date(from: sourceString) {
|
|
return date
|
|
}
|
|
}
|
|
}
|
|
if let sourceInt = source as? Int64 {
|
|
// treat as a java date
|
|
return Date(timeIntervalSince1970: Double(sourceInt / 1000) )
|
|
}
|
|
fatalError("formatter failed to parse \(source)")
|
|
} {{#models}}{{#model}}
|
|
|
|
// Decoder for [{{{classname}}}]
|
|
Decoders.addDecoder(clazz: [{{{classname}}}].self) { (source: AnyObject, instance: AnyObject?) -> [{{{classname}}}] in
|
|
return Decoders.decode(clazz: [{{{classname}}}].self, source: source)
|
|
}
|
|
// Decoder for {{{classname}}}
|
|
Decoders.addDecoder(clazz: {{{classname}}}.self) { (source: AnyObject, instance: AnyObject?) -> {{{classname}}} in
|
|
{{#isArrayModel}}
|
|
let sourceArray = source as! [AnyObject]
|
|
return sourceArray.map({ Decoders.decode(clazz: {{{arrayModelType}}}.self, source: $0, instance: nil) })
|
|
{{/isArrayModel}}
|
|
{{^isArrayModel}}
|
|
{{#isEnum}}
|
|
if let source = source as? {{dataType}} {
|
|
if let result = {{classname}}(rawValue: source) {
|
|
return result
|
|
}
|
|
}
|
|
fatalError("Source \(source) is not convertible to enum type {{classname}}: Maybe swagger file is insufficient")
|
|
{{/isEnum}}
|
|
{{^isEnum}}
|
|
{{#allVars.isEmpty}}
|
|
if let source = source as? {{dataType}} {
|
|
return source
|
|
}
|
|
fatalError("Source \(source) is not convertible to typealias {{classname}}: Maybe swagger file is insufficient")
|
|
{{/allVars.isEmpty}}
|
|
{{^allVars.isEmpty}}
|
|
let sourceDictionary = source as! [AnyHashable: Any]
|
|
{{#discriminator}}
|
|
// Check discriminator to support inheritance
|
|
if let discriminator = sourceDictionary["{{discriminator}}"] as? String, instance == nil && discriminator != "{{classname}}" {
|
|
return Decoders.decode(clazz: {{classname}}.self, discriminator: discriminator, source: source)
|
|
}
|
|
{{/discriminator}}
|
|
{{#additionalPropertiesType}}
|
|
var propsDictionary = sourceDictionary
|
|
let keys : [AnyHashable] = [{{#allVars}}{{^-last}}"{{baseName}}", {{/-last}}{{#-last}}"{{baseName}}"{{/-last}}{{/allVars}}]
|
|
{{/additionalPropertiesType}}
|
|
{{#unwrapRequired}}
|
|
let result = {{classname}}({{#requiredVars}}{{^-first}}, {{/-first}}{{#isEnum}}{{name}}: {{classname}}.{{datatypeWithEnum}}(rawValue: (sourceDictionary["{{baseName}}"] as! {{datatype}}))! {{/isEnum}}{{^isEnum}}{{name}}: Decoders.decode(clazz: {{{baseType}}}.self, source: sourceDictionary["{{baseName}}"]! as AnyObject, instance: nil){{/isEnum}}{{/requiredVars}})
|
|
{{#optionalVars}}{{#isEnum}}
|
|
if let {{name}} = sourceDictionary["{{baseName}}"] as? {{datatype}} { {{^isContainer}}
|
|
result.{{name}} = {{classname}}.{{datatypeWithEnum}}(rawValue: ({{name}})){{/isContainer}}{{#isListContainer}}
|
|
result.{{name}} = {{name}}.map ({ {{classname}}.{{enumName}}(rawValue: $0)! }){{/isListContainer}}
|
|
}{{/isEnum}}{{^isEnum}}
|
|
result.{{name}} = Decoders.decodeOptional(clazz: {{{baseType}}}.self, source: sourceDictionary["{{baseName}}"] as AnyObject?){{/isEnum}}
|
|
{{/optionalVars}}
|
|
{{/unwrapRequired}}
|
|
{{^unwrapRequired}}
|
|
let result = instance == nil ? {{classname}}() : instance as! {{classname}}
|
|
{{#parent}}
|
|
if decoders["\({{parent}}.self)"] != nil {
|
|
_ = Decoders.decode(clazz: {{parent}}.self, source: source, instance: result)
|
|
}
|
|
{{/parent}}
|
|
{{#allVars}}{{#isEnum}}
|
|
if let {{name}} = sourceDictionary["{{baseName}}"] as? {{datatype}} { {{^isContainer}}
|
|
result.{{name}} = {{classname}}.{{datatypeWithEnum}}(rawValue: ({{name}})){{/isContainer}}{{#isListContainer}}
|
|
result.{{name}} = {{name}}.map ({ {{classname}}.{{enumName}}(rawValue: $0)! }){{/isListContainer}}{{#isMapContainer}}//TODO: handle enum map scenario{{/isMapContainer}}
|
|
}{{/isEnum}}
|
|
{{^isEnum}}result.{{name}} = Decoders.decodeOptional(clazz: {{{baseType}}}.self, source: sourceDictionary["{{baseName}}"] as AnyObject?){{/isEnum}}{{/allVars}}
|
|
{{/unwrapRequired}}
|
|
{{#additionalPropertiesType}}
|
|
|
|
for key in keys {
|
|
propsDictionary.removeValue(forKey: key)
|
|
}
|
|
|
|
for key in propsDictionary.keys {
|
|
if let decodedValue = Decoders.decodeOptional(clazz: String.self, source: propsDictionary[key] as AnyObject?) {
|
|
result[key] = decodedValue
|
|
}
|
|
}
|
|
{{/additionalPropertiesType}}
|
|
return result
|
|
{{/allVars.isEmpty}}
|
|
{{/isEnum}}
|
|
{{/isArrayModel}}
|
|
}{{/model}}
|
|
{{/models}}
|
|
}()
|
|
|
|
static fileprivate func initialize() {
|
|
_ = Decoders.__once
|
|
}
|
|
}
|