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

Swift4: Support object schemas with only additionalProperties. #6492

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 @@ -85,6 +85,92 @@ extension UUID: JSONEncodable {
}
}

extension String: CodingKey {

public var stringValue: String {
return self
}

public init?(stringValue: String) {
self.init(stringLiteral: stringValue)
}

public var intValue: Int? {
return nil
}

public init?(intValue: Int) {
return nil
}

}

extension KeyedEncodingContainerProtocol {

public mutating func encodeArray<T>(_ values: [T], forKey key: Self.Key) throws where T : Encodable {
var arrayContainer = nestedUnkeyedContainer(forKey: key)
try arrayContainer.encode(contentsOf: values)
}

public mutating func encodeArrayIfPresent<T>(_ values: [T]?, forKey key: Self.Key) throws where T : Encodable {
if let values = values {
try encodeArray(values, forKey: key)
}
}

public mutating func encodeMap<T>(_ pairs: [Self.Key: T]) throws where T : Encodable {
for (key, value) in pairs {
try encode(value, forKey: key)
}
}

public mutating func encodeMapIfPresent<T>(_ pairs: [Self.Key: T]?) throws where T : Encodable {
if let pairs = pairs {
try encodeMap(pairs)
}
}

}

extension KeyedDecodingContainerProtocol {

public func decodeArray<T>(_ type: T.Type, forKey key: Self.Key) throws -> [T] where T : Decodable {
var tmpArray = [T]()

var nestedContainer = try nestedUnkeyedContainer(forKey: key)
while !nestedContainer.isAtEnd {
let arrayValue = try nestedContainer.decode(T.self)
tmpArray.append(arrayValue)
}

return tmpArray
}

public func decodeArrayIfPresent<T>(_ type: T.Type, forKey key: Self.Key) throws -> [T]? where T : Decodable {
var tmpArray: [T]? = nil

if contains(key) {
tmpArray = try decodeArray(T.self, forKey: key)
}

return tmpArray
}

public func decodeMap<T>(_ type: T.Type, excludedKeys: Set<Self.Key>) throws -> [Self.Key: T] where T : Decodable {
var map: [Self.Key : T] = [:]

for key in allKeys {
if !excludedKeys.contains(key) {
let value = try decode(T.self, forKey: key)
map[key] = value
}
}

return map
}

}

{{#usePromiseKit}}extension RequestBuilder {
public func execute() -> Promise<Response<T>> {
let deferred = Promise<Response<T>>.pending()
Expand Down
55 changes: 34 additions & 21 deletions modules/swagger-codegen/src/main/resources/swift4/model.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,7 @@ public enum {{classname}}: {{dataType}}, Codable {
}
{{/isEnum}}
{{^isEnum}}
{{#vars.isEmpty}}
public typealias {{classname}} = {{dataType}}
{{/vars.isEmpty}}
{{^vars.isEmpty}}

open class {{classname}}: {{#parent}}{{{parent}}}{{/parent}}{{^parent}}Codable{{/parent}} {

{{#vars}}
Expand All @@ -37,11 +34,11 @@ open class {{classname}}: {{#parent}}{{{parent}}}{{/parent}}{{^parent}}Codable{{
{{#vars}}
{{#isEnum}}
{{#description}}/** {{description}} */
{{/description}}public var {{name}}: {{{datatypeWithEnum}}}{{^unwrapRequired}}?{{/unwrapRequired}}{{#unwrapRequired}}{{^required}}?{{/required}}{{/unwrapRequired}}{{#defaultValue}} = {{{defaultValue}}}{{/defaultValue}}
{{/description}}public var {{name}}: {{{datatypeWithEnum}}}{{^required}}?{{/required}}{{#defaultValue}} = {{{defaultValue}}}{{/defaultValue}}
{{/isEnum}}
{{^isEnum}}
{{#description}}/** {{description}} */
{{/description}}public var {{name}}: {{{datatype}}}{{^unwrapRequired}}?{{/unwrapRequired}}{{#unwrapRequired}}{{^required}}?{{/required}}{{/unwrapRequired}}{{#defaultValue}} = {{{defaultValue}}}{{/defaultValue}}{{#objcCompatible}}{{#vendorExtensions.x-swift-optional-scalar}}
{{/description}}public var {{name}}: {{{datatype}}}{{^required}}?{{/required}}{{#defaultValue}} = {{{defaultValue}}}{{/defaultValue}}{{#objcCompatible}}{{#vendorExtensions.x-swift-optional-scalar}}
public var {{name}}Num: NSNumber? {
get {
return {{name}}.map({ return NSNumber(value: $0) })
Expand All @@ -51,19 +48,9 @@ open class {{classname}}: {{#parent}}{{{parent}}}{{/parent}}{{^parent}}Codable{{
{{/vars}}

{{#additionalPropertiesType}}
public var additionalProperties: [AnyHashable:{{{additionalPropertiesType}}}] = [:]
public var additionalProperties: [String:{{{additionalPropertiesType}}}] = [:]

{{/additionalPropertiesType}}
{{^unwrapRequired}}
{{^parent}}public init() {}{{/parent}}{{/unwrapRequired}}
{{#unwrapRequired}}
public init({{#allVars}}{{^-first}}, {{/-first}}{{name}}: {{#isEnum}}{{datatypeWithEnum}}{{/isEnum}}{{^isEnum}}{{datatype}}{{/isEnum}}{{^required}}?=nil{{/required}}{{/allVars}}) {
{{#vars}}
self.{{name}} = {{name}}
{{/vars}}
}{{/unwrapRequired}}
{{#additionalPropertiesType}}
public subscript(key: AnyHashable) -> {{{additionalPropertiesType}}}? {
public subscript(key: String) -> {{{additionalPropertiesType}}}? {
get {
if let value = additionalProperties[key] {
return value
Expand All @@ -77,12 +64,38 @@ open class {{classname}}: {{#parent}}{{{parent}}}{{/parent}}{{^parent}}Codable{{
}
{{/additionalPropertiesType}}

private enum CodingKeys: String, CodingKey { {{#vars}}
case {{{name}}} = "{{{baseName}}}"{{/vars}}
// Encodable protocol methods

public {{#parent}}override {{/parent}}func encode(to encoder: Encoder) throws {

var container = encoder.container(keyedBy: String.self)

{{#vars}}
try container.encode{{#isListContainer}}Array{{/isListContainer}}{{^required}}IfPresent{{/required}}({{{name}}}, forKey: "{{{baseName}}}")
{{/vars}}
{{#additionalPropertiesType}}
try container.encodeMap(additionalProperties)
{{/additionalPropertiesType}}
}

// Decodable protocol methods

public {{#parent}}override {{/parent}}required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: String.self)

{{#vars}}
{{name}} = try container.decode{{#isListContainer}}Array{{/isListContainer}}{{^required}}IfPresent{{/required}}({{#isListContainer}}{{{items.datatype}}}{{/isListContainer}}{{^isListContainer}}{{{datatype}}}{{/isListContainer}}.self, forKey: "{{{baseName}}}")
{{/vars}}
{{#additionalPropertiesType}}
var nonAdditionalPropertyKeys = Set<String>()
{{#vars}}
nonAdditionalPropertyKeys.insert("{{{baseName}}}")
{{/vars}}
additionalProperties = try container.decodeMap({{{additionalPropertiesType}}}.self, excludedKeys: nonAdditionalPropertyKeys)
{{/additionalPropertiesType}}
}
}
{{/vars.isEmpty}}

{{/isEnum}}
{{/isArrayModel}}
{{/model}}
Expand Down
66 changes: 66 additions & 0 deletions modules/swagger-codegen/src/test/resources/2_0/swift4Test.json
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,72 @@
}
},
"description": "Response object containing AllPrimitives object"
},
"ModelWithStringAdditionalPropertiesOnly": {
"description": "This is an empty model with no properties and only additionalProperties of type string",
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"ModelWithIntAdditionalPropertiesOnly": {
"description": "This is an empty model with no properties and only additionalProperties of type int32",
"type": "object",
"additionalProperties": {
"type": "integer",
"format": "int32"
}
},
"ModelWithPropertiesAndAdditionalProperties": {
"description": "This is an empty model with no properties and only additionalProperties of type int32",
"type": "object",
"required": [
"myIntegerReq",
"myPrimitiveReq",
"myStringArrayReq",
"myPrimitiveArrayReq"
],
"properties": {
"myIntegerReq": {
"type": "integer"
},
"myIntegerOpt": {
"type": "integer"
},
"myPrimitiveReq": {
"$ref": "#/definitions/AllPrimitives"
},
"myPrimitiveOpt": {
"$ref": "#/definitions/AllPrimitives"
},
"myStringArrayReq": {
"type": "array",
"items": {
"type": "string"
}
},
"myStringArrayOpt": {
"type": "array",
"items": {
"type": "string"
}
},
"myPrimitiveArrayReq": {
"type": "array",
"items": {
"$ref": "#/definitions/AllPrimitives"
}
},
"myPrimitiveArrayOpt": {
"type": "array",
"items": {
"$ref": "#/definitions/AllPrimitives"
}
}
},
"additionalProperties": {
"type": "string"
}
}
}
}
4 changes: 2 additions & 2 deletions samples/client/test/swift4/default/TestClient.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ Pod::Spec.new do |s|
s.license = 'Proprietary'
s.homepage = 'https://github.com/swagger-api/swagger-codegen'
s.summary = 'TestClient'
s.source_files = 'TestClient/Classes/Swaggers/**/*.swift'
s.dependency 'Alamofire', '~> 4.5'
s.source_files = 'TestClient/Classes/**/*.swift'
s.dependency 'Alamofire', '~> 4.5.0'
end
Original file line number Diff line number Diff line change
Expand Up @@ -30,60 +30,85 @@ open class Swift4TestAPI {
- This endpoint tests get a dictionary which contains examples of all of the models.
- examples: [{contentType=application/json, example={
"myPrimitive" : {
"myDateTimeArray" : [ "2000-01-23T04:56:07.000+00:00" ],
"myStringArray" : [ "aeiou" ],
"myDateTimeArray" : [ "2000-01-23T04:56:07.000+00:00", "2000-01-23T04:56:07.000+00:00" ],
"myStringArray" : [ "myStringArray", "myStringArray" ],
"myFile" : "",
"myFloatArray" : [ 2.302136 ],
"myBytes" : "aeiou",
"myFloatArray" : [ 2.302136, 2.302136 ],
"myBytes" : "myBytes",
"myLong" : 1,
"myBooleanArray" : [ true ],
"myDoubleArray" : [ 9.301444243932576 ],
"myBooleanArray" : [ true, true ],
"myDoubleArray" : [ 9.301444243932576, 9.301444243932576 ],
"myInteger" : 0,
"myString" : "aeiou",
"myBytesArray" : [ "aeiou" ],
"myString" : "myString",
"myBytesArray" : [ "myBytesArray", "myBytesArray" ],
"myDouble" : 7.061401241503109,
"myDate" : "2000-01-23",
"myDateArray" : [ "2000-01-23" ],
"myDateArray" : [ "2000-01-23", "2000-01-23" ],
"myDateTime" : "2000-01-23T04:56:07.000+00:00",
"myLongArray" : [ 5 ],
"myIntegerArray" : [ 6 ],
"myLongArray" : [ 5, 5 ],
"myIntegerArray" : [ 6, 6 ],
"myUUID" : "046b6c7f-0b8a-43b9-b35d-6489e6daee91",
"myBoolean" : true,
"myFileArray" : [ "" ],
"myFileArray" : [ "", "" ],
"myStringEnum" : { },
"myFloat" : 5.637377,
"myStringEnumArray" : [ null ],
"myUUIDArray" : [ "046b6c7f-0b8a-43b9-b35d-6489e6daee91" ]
"myStringEnumArray" : [ null, null ],
"myUUIDArray" : [ "046b6c7f-0b8a-43b9-b35d-6489e6daee91", "046b6c7f-0b8a-43b9-b35d-6489e6daee91" ]
},
"myVariableNameTest" : {
"for" : "aeiou",
"example_name" : "aeiou"
"for" : "for",
"example_name" : "example_name"
},
"myPrimitiveArray" : [ {
"myDateTimeArray" : [ "2000-01-23T04:56:07.000+00:00" ],
"myStringArray" : [ "aeiou" ],
"myDateTimeArray" : [ "2000-01-23T04:56:07.000+00:00", "2000-01-23T04:56:07.000+00:00" ],
"myStringArray" : [ "myStringArray", "myStringArray" ],
"myFile" : "",
"myFloatArray" : [ 2.302136 ],
"myBytes" : "aeiou",
"myFloatArray" : [ 2.302136, 2.302136 ],
"myBytes" : "myBytes",
"myLong" : 1,
"myBooleanArray" : [ true ],
"myDoubleArray" : [ 9.301444243932576 ],
"myBooleanArray" : [ true, true ],
"myDoubleArray" : [ 9.301444243932576, 9.301444243932576 ],
"myInteger" : 0,
"myString" : "aeiou",
"myBytesArray" : [ "aeiou" ],
"myString" : "myString",
"myBytesArray" : [ "myBytesArray", "myBytesArray" ],
"myDouble" : 7.061401241503109,
"myDate" : "2000-01-23",
"myDateArray" : [ "2000-01-23" ],
"myDateArray" : [ "2000-01-23", "2000-01-23" ],
"myDateTime" : "2000-01-23T04:56:07.000+00:00",
"myLongArray" : [ 5 ],
"myIntegerArray" : [ 6 ],
"myLongArray" : [ 5, 5 ],
"myIntegerArray" : [ 6, 6 ],
"myUUID" : "046b6c7f-0b8a-43b9-b35d-6489e6daee91",
"myBoolean" : true,
"myFileArray" : [ "" ],
"myFileArray" : [ "", "" ],
"myStringEnum" : { },
"myFloat" : 5.637377,
"myStringEnumArray" : [ null ],
"myUUIDArray" : [ "046b6c7f-0b8a-43b9-b35d-6489e6daee91" ]
"myStringEnumArray" : [ null, null ],
"myUUIDArray" : [ "046b6c7f-0b8a-43b9-b35d-6489e6daee91", "046b6c7f-0b8a-43b9-b35d-6489e6daee91" ]
}, {
"myDateTimeArray" : [ "2000-01-23T04:56:07.000+00:00", "2000-01-23T04:56:07.000+00:00" ],
"myStringArray" : [ "myStringArray", "myStringArray" ],
"myFile" : "",
"myFloatArray" : [ 2.302136, 2.302136 ],
"myBytes" : "myBytes",
"myLong" : 1,
"myBooleanArray" : [ true, true ],
"myDoubleArray" : [ 9.301444243932576, 9.301444243932576 ],
"myInteger" : 0,
"myString" : "myString",
"myBytesArray" : [ "myBytesArray", "myBytesArray" ],
"myDouble" : 7.061401241503109,
"myDate" : "2000-01-23",
"myDateArray" : [ "2000-01-23", "2000-01-23" ],
"myDateTime" : "2000-01-23T04:56:07.000+00:00",
"myLongArray" : [ 5, 5 ],
"myIntegerArray" : [ 6, 6 ],
"myUUID" : "046b6c7f-0b8a-43b9-b35d-6489e6daee91",
"myBoolean" : true,
"myFileArray" : [ "", "" ],
"myStringEnum" : { },
"myFloat" : 5.637377,
"myStringEnumArray" : [ null, null ],
"myUUIDArray" : [ "046b6c7f-0b8a-43b9-b35d-6489e6daee91", "046b6c7f-0b8a-43b9-b35d-6489e6daee91" ]
} ]
}}]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ open class CodableHelper {
var returnedError: Error? = nil

let decoder = JSONDecoder()
decoder.dataDecodingStrategy = .base64Decode
decoder.dataDecodingStrategy = .base64
if #available(iOS 10.0, *) {
decoder.dateDecodingStrategy = .iso8601
}
Expand All @@ -38,7 +38,7 @@ open class CodableHelper {
if prettyPrint {
encoder.outputFormatting = .prettyPrinted
}
encoder.dataEncodingStrategy = .base64Encode
encoder.dataEncodingStrategy = .base64
if #available(iOS 10.0, *) {
encoder.dateEncodingStrategy = .iso8601
}
Expand Down
Loading