Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Swift3] decoders call parents decoders to fix issue with class inheritance #5369

Merged
merged 1 commit into from
Apr 17, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ open class AlamofireRequestBuilder<T>: RequestBuilder<T> {
return
}
if let json: Any = response.result.value {
let body = Decoders.decode(clazz: T.self, source: json as AnyObject)
let body = Decoders.decode(clazz: T.self, source: json as AnyObject, instance: nil)
completion(Response(response: response.response!, body: body), nil)
return
} else if "" is T {
Expand Down
48 changes: 26 additions & 22 deletions modules/swagger-codegen/src/main/resources/swift3/Models.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -37,37 +37,37 @@ open class Response<T> {

private var once = Int()
class Decoders {
static fileprivate var decoders = Dictionary<String, ((AnyObject) -> AnyObject)>()
static fileprivate var decoders = Dictionary<String, ((AnyObject, AnyObject?) -> AnyObject)>()

static func addDecoder<T>(clazz: T.Type, decoder: @escaping ((AnyObject) -> T)) {
static func addDecoder<T>(clazz: T.Type, decoder: @escaping ((AnyObject, AnyObject?) -> T)) {
let key = "\(T.self)"
decoders[key] = { decoder($0) as AnyObject }
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) as! T
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) }
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)
dictionary[key] = Decoders.decode(clazz: T.self, source: value, instance: nil)
}
return dictionary
}

static func decode<T>(clazz: T.Type, source: AnyObject) -> T {
static func decode<T>(clazz: T.Type, source: AnyObject, instance: AnyObject?) -> T {
initialize()
if T.self is Int32.Type && source is NSNumber {
return source.int32Value as! T;
Expand All @@ -87,7 +87,7 @@ class Decoders {

let key = "\(T.self)"
if let decoder = decoders[key] {
return decoder(source) as! T
return decoder(source, instance) as! T
} else {
fatalError("Source \(source) is not convertible to type \(clazz): Maybe swagger file is insufficient")
}
Expand All @@ -98,7 +98,7 @@ class Decoders {
return nil
}
return source.map { (source: AnyObject) -> T in
Decoders.decode(clazz: clazz, source: source)
Decoders.decode(clazz: clazz, source: source, instance: nil)
}
}

Expand Down Expand Up @@ -134,7 +134,7 @@ class Decoders {
return formatter
}
// Decoder for Date
Decoders.addDecoder(clazz: Date.self) { (source: AnyObject) -> Date in
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) {
Expand All @@ -150,14 +150,14 @@ class Decoders {
} {{#models}}{{#model}}

// Decoder for [{{{classname}}}]
Decoders.addDecoder(clazz: [{{{classname}}}].self) { (source: AnyObject) -> [{{{classname}}}] in
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) -> {{{classname}}} in
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) })
return sourceArray.map({ Decoders.decode(clazz: {{{arrayModelType}}}.self, source: $0, instance: nil) })
{{/isArrayModel}}
{{^isArrayModel}}
{{#isEnum}}
Expand Down Expand Up @@ -185,24 +185,28 @@ class Decoders {
{{/discriminator}}

{{#unwrapRequired}}
let instance = {{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){{/isEnum}}{{/requiredVars}})
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}}
instance.{{name}} = {{classname}}.{{datatypeWithEnum}}(rawValue: ({{name}})){{/isContainer}}{{#isListContainer}}
instance.{{name}} = {{name}}.map ({ {{classname}}.{{enumName}}(rawValue: $0)! }){{/isListContainer}}
result.{{name}} = {{classname}}.{{datatypeWithEnum}}(rawValue: ({{name}})){{/isContainer}}{{#isListContainer}}
result.{{name}} = {{name}}.map ({ {{classname}}.{{enumName}}(rawValue: $0)! }){{/isListContainer}}
}{{/isEnum}}{{^isEnum}}
instance.{{name}} = Decoders.decodeOptional(clazz: {{{baseType}}}.self, source: sourceDictionary["{{baseName}}"] as AnyObject?){{/isEnum}}
result.{{name}} = Decoders.decodeOptional(clazz: {{{baseType}}}.self, source: sourceDictionary["{{baseName}}"] as AnyObject?){{/isEnum}}
{{/optionalVars}}
{{/unwrapRequired}}
{{^unwrapRequired}}
let instance = {{classname}}(){{#allVars}}{{#isEnum}}
let result = instance == nil ? {{classname}}() : instance as! {{classname}}
{{#parent}}
_ = Decoders.decode(clazz: {{parent}}.self, source: source, instance: result)
{{/parent}}
{{#allVars}}{{#isEnum}}
if let {{name}} = sourceDictionary["{{baseName}}"] as? {{datatype}} { {{^isContainer}}
instance.{{name}} = {{classname}}.{{datatypeWithEnum}}(rawValue: ({{name}})){{/isContainer}}{{#isListContainer}}
instance.{{name}} = {{name}}.map ({ {{classname}}.{{enumName}}(rawValue: $0)! }){{/isListContainer}}{{#isMapContainer}}//TODO: handle enum map scenario{{/isMapContainer}}
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}}instance.{{name}} = Decoders.decodeOptional(clazz: {{{baseType}}}.self, source: sourceDictionary["{{baseName}}"] as AnyObject?){{/isEnum}}{{/allVars}}
{{^isEnum}}result.{{name}} = Decoders.decodeOptional(clazz: {{{baseType}}}.self, source: sourceDictionary["{{baseName}}"] as AnyObject?){{/isEnum}}{{/allVars}}
{{/unwrapRequired}}
return instance
return result
{{/allVars.isEmpty}}
{{/isEnum}}
{{/isArrayModel}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ open class FakeAPI: APIBase {
To test \"client\" model
- PATCH /fake
- To test \"client\" model
- examples: [{contentType=application/json, example={
- examples: [{example={
"client" : "aeiou"
}}]
}, contentType=application/json}]

- parameter body: (body) client model

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ open class PetAPI: APIBase {
- OAuth:
- type: oauth2
- name: petstore_auth
- examples: [{contentType=application/xml, example=<Pet>
- examples: [{example=<Pet>
<id>123456789</id>
<name>doggie</name>
<photoUrls>
Expand All @@ -131,21 +131,21 @@ open class PetAPI: APIBase {
<tags>
</tags>
<status>aeiou</status>
</Pet>}, {contentType=application/json, example=[ {
"photoUrls" : [ "aeiou" ],
"name" : "doggie",
</Pet>, contentType=application/xml}, {example=[ {
"tags" : [ {
"id" : 1,
"name" : "aeiou"
} ],
"id" : 0,
"category" : {
"name" : "aeiou",
"id" : 6
"id" : 6,
"name" : "aeiou"
},
"tags" : [ {
"name" : "aeiou",
"id" : 1
} ],
"status" : "available"
} ]}]
- examples: [{contentType=application/xml, example=<Pet>
"status" : "available",
"name" : "doggie",
"photoUrls" : [ "aeiou" ]
} ], contentType=application/json}]
- examples: [{example=<Pet>
<id>123456789</id>
<name>doggie</name>
<photoUrls>
Expand All @@ -154,20 +154,20 @@ open class PetAPI: APIBase {
<tags>
</tags>
<status>aeiou</status>
</Pet>}, {contentType=application/json, example=[ {
"photoUrls" : [ "aeiou" ],
"name" : "doggie",
</Pet>, contentType=application/xml}, {example=[ {
"tags" : [ {
"id" : 1,
"name" : "aeiou"
} ],
"id" : 0,
"category" : {
"name" : "aeiou",
"id" : 6
"id" : 6,
"name" : "aeiou"
},
"tags" : [ {
"name" : "aeiou",
"id" : 1
} ],
"status" : "available"
} ]}]
"status" : "available",
"name" : "doggie",
"photoUrls" : [ "aeiou" ]
} ], contentType=application/json}]

- parameter status: (query) Status values that need to be considered for filter

Expand Down Expand Up @@ -209,7 +209,7 @@ open class PetAPI: APIBase {
- OAuth:
- type: oauth2
- name: petstore_auth
- examples: [{contentType=application/xml, example=<Pet>
- examples: [{example=<Pet>
<id>123456789</id>
<name>doggie</name>
<photoUrls>
Expand All @@ -218,21 +218,21 @@ open class PetAPI: APIBase {
<tags>
</tags>
<status>aeiou</status>
</Pet>}, {contentType=application/json, example=[ {
"photoUrls" : [ "aeiou" ],
"name" : "doggie",
</Pet>, contentType=application/xml}, {example=[ {
"tags" : [ {
"id" : 1,
"name" : "aeiou"
} ],
"id" : 0,
"category" : {
"name" : "aeiou",
"id" : 6
"id" : 6,
"name" : "aeiou"
},
"tags" : [ {
"name" : "aeiou",
"id" : 1
} ],
"status" : "available"
} ]}]
- examples: [{contentType=application/xml, example=<Pet>
"status" : "available",
"name" : "doggie",
"photoUrls" : [ "aeiou" ]
} ], contentType=application/json}]
- examples: [{example=<Pet>
<id>123456789</id>
<name>doggie</name>
<photoUrls>
Expand All @@ -241,20 +241,20 @@ open class PetAPI: APIBase {
<tags>
</tags>
<status>aeiou</status>
</Pet>}, {contentType=application/json, example=[ {
"photoUrls" : [ "aeiou" ],
"name" : "doggie",
</Pet>, contentType=application/xml}, {example=[ {
"tags" : [ {
"id" : 1,
"name" : "aeiou"
} ],
"id" : 0,
"category" : {
"name" : "aeiou",
"id" : 6
"id" : 6,
"name" : "aeiou"
},
"tags" : [ {
"name" : "aeiou",
"id" : 1
} ],
"status" : "available"
} ]}]
"status" : "available",
"name" : "doggie",
"photoUrls" : [ "aeiou" ]
} ], contentType=application/json}]

- parameter tags: (query) Tags to filter by

Expand Down Expand Up @@ -296,7 +296,7 @@ open class PetAPI: APIBase {
- API Key:
- type: apiKey api_key
- name: api_key
- examples: [{contentType=application/xml, example=<Pet>
- examples: [{example=<Pet>
<id>123456789</id>
<name>doggie</name>
<photoUrls>
Expand All @@ -305,21 +305,21 @@ open class PetAPI: APIBase {
<tags>
</tags>
<status>aeiou</status>
</Pet>}, {contentType=application/json, example={
"photoUrls" : [ "aeiou" ],
"name" : "doggie",
</Pet>, contentType=application/xml}, {example={
"tags" : [ {
"id" : 1,
"name" : "aeiou"
} ],
"id" : 0,
"category" : {
"name" : "aeiou",
"id" : 6
"id" : 6,
"name" : "aeiou"
},
"tags" : [ {
"name" : "aeiou",
"id" : 1
} ],
"status" : "available"
}}]
- examples: [{contentType=application/xml, example=<Pet>
"status" : "available",
"name" : "doggie",
"photoUrls" : [ "aeiou" ]
}, contentType=application/json}]
- examples: [{example=<Pet>
<id>123456789</id>
<name>doggie</name>
<photoUrls>
Expand All @@ -328,20 +328,20 @@ open class PetAPI: APIBase {
<tags>
</tags>
<status>aeiou</status>
</Pet>}, {contentType=application/json, example={
"photoUrls" : [ "aeiou" ],
"name" : "doggie",
</Pet>, contentType=application/xml}, {example={
"tags" : [ {
"id" : 1,
"name" : "aeiou"
} ],
"id" : 0,
"category" : {
"name" : "aeiou",
"id" : 6
"id" : 6,
"name" : "aeiou"
},
"tags" : [ {
"name" : "aeiou",
"id" : 1
} ],
"status" : "available"
}}]
"status" : "available",
"name" : "doggie",
"photoUrls" : [ "aeiou" ]
}, contentType=application/json}]

- parameter petId: (path) ID of pet to return

Expand Down Expand Up @@ -470,11 +470,11 @@ open class PetAPI: APIBase {
- OAuth:
- type: oauth2
- name: petstore_auth
- examples: [{contentType=application/json, example={
- examples: [{example={
"message" : "aeiou",
"code" : 0,
"type" : "aeiou",
"message" : "aeiou"
}}]
"type" : "aeiou"
}, contentType=application/json}]

- parameter petId: (path) ID of pet to update
- parameter additionalMetadata: (form) Additional data to pass to server (optional)
Expand Down
Loading