Skip to content

Commit 0f5e7d1

Browse files
authored
Swift5 models improvements (#9205)
* [swift5] Add useClasses to use `final class` instead of `struct` * [swift5] Always include CodingKeys enum * [swift5] Implement model equals and hash functions * [swift5] Encode `null` values * [swift5] Test `useClasses` in urlsessionLibrary * [swift5] Add a required nullable prop test case to 2_0/swift/petstore*.yaml * [swift5] Update samples and docs
1 parent 22950fa commit 0f5e7d1

414 files changed

Lines changed: 6684 additions & 342 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

bin/configs/swift5-urlsessionLibrary.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ additionalProperties:
1010
projectName: PetstoreClient
1111
podHomepage: https://github.com/openapitools/openapi-generator
1212
useSPMFileStructure: true
13+
useClasses: true

docs/generators/swift5.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
1414
|hideGenerationTimestamp|Hides the generation timestamp when files are generated.| |true|
1515
|legacyDiscriminatorBehavior|Set to false for generators with better support for discriminators. (Python, Java, Go, PowerShell, C#have this enabled by default).|<dl><dt>**true**</dt><dd>The mapping in the discriminator includes descendent schemas that allOf inherit from self and the discriminator mapping schemas in the OAS document.</dd><dt>**false**</dt><dd>The mapping in the discriminator includes any descendent schemas that allOf inherit from self, any oneOf schemas, any anyOf schemas, any x-discriminator-values, and the discriminator mapping schemas in the OAS document AND Codegen validates that oneOf and anyOf schemas contain the required discriminator and throws an error if the discriminator is missing.</dd></dl>|true|
1616
|lenientTypeCast|Accept and cast values for simple types (string-&gt;bool, string-&gt;int, int-&gt;string)| |false|
17-
|library|Library template (sub-template) to use|<dl><dt>**urlsession**</dt><dd>[DEFAULT] HTTP client: URLSession</dd><dt>**alamofire**</dt><dd>HTTP client: Alamofire</dd><dt>**vapor**</dt><dd>HTTP client: Vapor</dd></dl>|urlsession|
17+
|library|Library template (sub-template) to use|<dl><dt>**urlsession**</dt><dd>[DEFAULT] HTTP client: URLSession</dd><dt>**alamofire**</dt><dd>HTTP client: Alamofire</dd></dl>|urlsession|
1818
|nonPublicApi|Generates code with reduced access modifiers; allows embedding elsewhere without exposing non-public API calls to consumers.(default: false)| |null|
1919
|objcCompatible|Add additional properties and methods for Objective-C compatibility (default: false)| |null|
2020
|podAuthors|Authors used for Podspec| |null|

modules/openapi-generator/src/main/resources/swift5/modelObject.mustache

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{{^objcCompatible}}{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} struct {{classname}}: Codable, Hashable {
1+
{{^objcCompatible}}{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} {{#useClasses}}final class{{/useClasses}}{{^useClasses}}struct{{/useClasses}} {{classname}}: Codable, Hashable {
22
{{/objcCompatible}}{{#objcCompatible}}@objc {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} class {{classname}}: NSObject, Codable {
33
{{/objcCompatible}}
44

@@ -36,6 +36,11 @@
3636
{{/allVars}}
3737
}
3838
{{/hasVars}}
39+
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum CodingKeys: {{#hasVars}}String, {{/hasVars}}CodingKey, CaseIterable {
40+
{{#allVars}}
41+
case {{{name}}}{{#vendorExtensions.x-codegen-escaped-property-name}} = "{{{baseName}}}"{{/vendorExtensions.x-codegen-escaped-property-name}}
42+
{{/allVars}}
43+
}
3944
{{#additionalPropertiesType}}
4045
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} {{#readonlyProperties}}private(set) {{/readonlyProperties}}var additionalProperties: [String: {{{additionalPropertiesType}}}] = [:]
4146

@@ -51,19 +56,22 @@
5156
additionalProperties[key] = newValue
5257
}
5358
}
59+
{{/additionalPropertiesType}}
5460

5561
// Encodable protocol methods
5662

5763
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} func encode(to encoder: Encoder) throws {
58-
59-
var container = encoder.container(keyedBy: String.self)
60-
64+
var container = encoder.container(keyedBy: CodingKeys.self)
6165
{{#allVars}}
62-
try container.encode{{#required}}{{#isNullable}}IfPresent{{/isNullable}}{{/required}}{{^required}}IfPresent{{/required}}({{{name}}}, forKey: "{{{baseName}}}")
66+
try container.encode{{^required}}IfPresent{{/required}}({{{name}}}, forKey: .{{{name}}})
6367
{{/allVars}}
64-
try container.encodeMap(additionalProperties)
68+
{{#additionalPropertiesType}}
69+
var additionalPropertiesContainer = encoder.container(keyedBy: String.self)
70+
try additionalPropertiesContainer.encodeMap(additionalProperties)
71+
{{/additionalPropertiesType}}
6572
}
6673

74+
{{#additionalPropertiesType}}
6775
// Decodable protocol methods
6876

6977
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}}{{#objcCompatible}} required{{/objcCompatible}} init(from decoder: Decoder) throws {
@@ -79,11 +87,20 @@
7987
additionalProperties = try container.decodeMap({{{additionalPropertiesType}}}.self, excludedKeys: nonAdditionalPropertyKeys)
8088
}
8189
{{/additionalPropertiesType}}
82-
{{^additionalPropertiesType}}{{#vendorExtensions.x-codegen-has-escaped-property-names}}
83-
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum CodingKeys: String, CodingKey, CaseIterable {
90+
91+
{{^objcCompatible}}{{#useClasses}}
92+
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} static func == (lhs: {{classname}}, rhs: {{classname}}) -> Bool {
8493
{{#allVars}}
85-
case {{{name}}}{{#vendorExtensions.x-codegen-escaped-property-name}} = "{{{baseName}}}"{{/vendorExtensions.x-codegen-escaped-property-name}}
94+
lhs.{{{name}}} == rhs.{{{name}}}{{^-last}} &&{{/-last}}
95+
{{/allVars}}
96+
{{#additionalPropertiesType}}{{#hasVars}}&& {{/hasVars}}lhs.additionalProperties == rhs.additionalProperties{{/additionalPropertiesType}}
97+
}
98+
99+
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} func hash(into hasher: inout Hasher) {
100+
{{#allVars}}
101+
hasher.combine({{{name}}}{{^required}}?{{/required}}.hashValue)
86102
{{/allVars}}
103+
{{#additionalPropertiesType}}hasher.combine(additionalProperties.hashValue){{/additionalPropertiesType}}
87104
}
88-
{{/vendorExtensions.x-codegen-has-escaped-property-names}}{{/additionalPropertiesType}}
105+
{{/useClasses}}{{/objcCompatible}}
89106
}

modules/openapi-generator/src/test/resources/2_0/swift/petstore-with-fake-endpoints-models-for-testing.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,6 +1096,7 @@ definitions:
10961096
name:
10971097
type: string
10981098
default: default-name
1099+
x-nullable: true
10991100
xml:
11001101
name: Category
11011102
User:

samples/client/petstore/swift5/alamofireLibrary/PetstoreClient/Classes/OpenAPIs/Models/AdditionalPropertiesClass.swift

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,19 @@ public struct AdditionalPropertiesClass: Codable, Hashable {
1616
self.mapString = mapString
1717
self.mapMapString = mapMapString
1818
}
19-
2019
public enum CodingKeys: String, CodingKey, CaseIterable {
2120
case mapString = "map_string"
2221
case mapMapString = "map_map_string"
2322
}
2423

24+
// Encodable protocol methods
25+
26+
public func encode(to encoder: Encoder) throws {
27+
var container = encoder.container(keyedBy: CodingKeys.self)
28+
try container.encodeIfPresent(mapString, forKey: .mapString)
29+
try container.encodeIfPresent(mapMapString, forKey: .mapMapString)
30+
}
31+
32+
33+
2534
}

samples/client/petstore/swift5/alamofireLibrary/PetstoreClient/Classes/OpenAPIs/Models/Animal.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,19 @@ public struct Animal: Codable, Hashable {
1616
self.className = className
1717
self.color = color
1818
}
19+
public enum CodingKeys: String, CodingKey, CaseIterable {
20+
case className
21+
case color
22+
}
23+
24+
// Encodable protocol methods
25+
26+
public func encode(to encoder: Encoder) throws {
27+
var container = encoder.container(keyedBy: CodingKeys.self)
28+
try container.encode(className, forKey: .className)
29+
try container.encodeIfPresent(color, forKey: .color)
30+
}
31+
32+
1933

2034
}

samples/client/petstore/swift5/alamofireLibrary/PetstoreClient/Classes/OpenAPIs/Models/ApiResponse.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,21 @@ public struct ApiResponse: Codable, Hashable {
1818
self.type = type
1919
self.message = message
2020
}
21+
public enum CodingKeys: String, CodingKey, CaseIterable {
22+
case code
23+
case type
24+
case message
25+
}
26+
27+
// Encodable protocol methods
28+
29+
public func encode(to encoder: Encoder) throws {
30+
var container = encoder.container(keyedBy: CodingKeys.self)
31+
try container.encodeIfPresent(code, forKey: .code)
32+
try container.encodeIfPresent(type, forKey: .type)
33+
try container.encodeIfPresent(message, forKey: .message)
34+
}
35+
36+
2137

2238
}

samples/client/petstore/swift5/alamofireLibrary/PetstoreClient/Classes/OpenAPIs/Models/ArrayOfArrayOfNumberOnly.swift

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,17 @@ public struct ArrayOfArrayOfNumberOnly: Codable, Hashable {
1414
public init(arrayArrayNumber: [[Double]]? = nil) {
1515
self.arrayArrayNumber = arrayArrayNumber
1616
}
17-
1817
public enum CodingKeys: String, CodingKey, CaseIterable {
1918
case arrayArrayNumber = "ArrayArrayNumber"
2019
}
2120

21+
// Encodable protocol methods
22+
23+
public func encode(to encoder: Encoder) throws {
24+
var container = encoder.container(keyedBy: CodingKeys.self)
25+
try container.encodeIfPresent(arrayArrayNumber, forKey: .arrayArrayNumber)
26+
}
27+
28+
29+
2230
}

samples/client/petstore/swift5/alamofireLibrary/PetstoreClient/Classes/OpenAPIs/Models/ArrayOfNumberOnly.swift

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,17 @@ public struct ArrayOfNumberOnly: Codable, Hashable {
1414
public init(arrayNumber: [Double]? = nil) {
1515
self.arrayNumber = arrayNumber
1616
}
17-
1817
public enum CodingKeys: String, CodingKey, CaseIterable {
1918
case arrayNumber = "ArrayNumber"
2019
}
2120

21+
// Encodable protocol methods
22+
23+
public func encode(to encoder: Encoder) throws {
24+
var container = encoder.container(keyedBy: CodingKeys.self)
25+
try container.encodeIfPresent(arrayNumber, forKey: .arrayNumber)
26+
}
27+
28+
29+
2230
}

samples/client/petstore/swift5/alamofireLibrary/PetstoreClient/Classes/OpenAPIs/Models/ArrayTest.swift

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,21 @@ public struct ArrayTest: Codable, Hashable {
1818
self.arrayArrayOfInteger = arrayArrayOfInteger
1919
self.arrayArrayOfModel = arrayArrayOfModel
2020
}
21-
2221
public enum CodingKeys: String, CodingKey, CaseIterable {
2322
case arrayOfString = "array_of_string"
2423
case arrayArrayOfInteger = "array_array_of_integer"
2524
case arrayArrayOfModel = "array_array_of_model"
2625
}
2726

27+
// Encodable protocol methods
28+
29+
public func encode(to encoder: Encoder) throws {
30+
var container = encoder.container(keyedBy: CodingKeys.self)
31+
try container.encodeIfPresent(arrayOfString, forKey: .arrayOfString)
32+
try container.encodeIfPresent(arrayArrayOfInteger, forKey: .arrayArrayOfInteger)
33+
try container.encodeIfPresent(arrayArrayOfModel, forKey: .arrayArrayOfModel)
34+
}
35+
36+
37+
2838
}

0 commit comments

Comments
 (0)