From 4f0b7dfaed9ce0ffbc2284d4fa348c2cd45e794e Mon Sep 17 00:00:00 2001 From: Jason Gavris Date: Thu, 30 Jun 2016 14:31:31 -0400 Subject: [PATCH] [Swift] Handle binary data types --- .../codegen/languages/ObjcClientCodegen.java | 2 + .../codegen/languages/SwiftCodegen.java | 12 ++-- .../swift/AlamofireImplementations.mustache | 69 +++++++++++++------ .../main/resources/swift/Extensions.mustache | 5 ++ .../src/main/resources/swift/Models.mustache | 3 + .../SwiftCodegenTest.java | 23 ++++++- .../swagger/codegen/swift/SwiftModelTest.java | 34 +++++++-- .../Swaggers/AlamofireImplementations.swift | 69 +++++++++++++------ .../Classes/Swaggers/Extensions.swift | 5 ++ .../Classes/Swaggers/Models.swift | 3 + 10 files changed, 174 insertions(+), 51 deletions(-) rename modules/swagger-codegen/src/test/java/io/swagger/codegen/{languages => swift}/SwiftCodegenTest.java (66%) diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ObjcClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ObjcClientCodegen.java index e028083a74..d8b20ae5dd 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ObjcClientCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ObjcClientCodegen.java @@ -703,6 +703,8 @@ public class ObjcClientCodegen extends DefaultCodegen implements CodegenConfig { example = "2013-10-20T19:20:30+01:00"; } example = "@\"" + escapeText(example) + "\""; + } else if ("NSData".equalsIgnoreCase(type)) { + example = "1234"; } else if (!languageSpecificPrimitives.contains(type)) { // type is a model class, e.g. User type = type.replace("*", ""); diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/SwiftCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/SwiftCodegen.java index b782e3626f..3335be6bdc 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/SwiftCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/SwiftCodegen.java @@ -87,6 +87,7 @@ public class SwiftCodegen extends DefaultCodegen implements CodegenConfig { ); defaultIncludes = new HashSet( Arrays.asList( + "NSData", "NSDate", "NSURL", // for file "NSUUID", @@ -129,10 +130,8 @@ public class SwiftCodegen extends DefaultCodegen implements CodegenConfig { typeMapping.put("double", "Double"); typeMapping.put("object", "AnyObject"); typeMapping.put("file", "NSURL"); - //TODO binary should be mapped to byte array - // mapped to String as a workaround - typeMapping.put("binary", "String"); - typeMapping.put("ByteArray", "String"); + typeMapping.put("binary", "NSData"); + typeMapping.put("ByteArray", "NSData"); typeMapping.put("UUID", "NSUUID"); importMapping = new HashMap(); @@ -258,6 +257,11 @@ public class SwiftCodegen extends DefaultCodegen implements CodegenConfig { return toModelName(type); } + @Override + public boolean isDataTypeBinary(final String dataType) { + return dataType != null && dataType.equals("NSData"); + } + /** * Output the proper model name (capitalized) * diff --git a/modules/swagger-codegen/src/main/resources/swift/AlamofireImplementations.mustache b/modules/swagger-codegen/src/main/resources/swift/AlamofireImplementations.mustache index 0b153ad17d..cabf67567b 100644 --- a/modules/swagger-codegen/src/main/resources/swift/AlamofireImplementations.mustache +++ b/modules/swagger-codegen/src/main/resources/swift/AlamofireImplementations.mustache @@ -82,30 +82,59 @@ class AlamofireRequestBuilder: RequestBuilder { request.authenticate(usingCredential: credential) } - request.validate().responseJSON(options: .AllowFragments) { response in + let cleanupRequest = { managerStore.removeValueForKey(managerId) + } - if response.result.isFailure { - completion(response: nil, error: response.result.error) - return - } + let validatedRequest = request.validate() - if () is T { - completion(response: Response(response: response.response!, body: () as! T), error: nil) - return - } - if let json: AnyObject = response.result.value { - let body = Decoders.decode(clazz: T.self, source: json) - completion(response: Response(response: response.response!, body: body), error: nil) - return - } else if "" is T { - // swagger-parser currently doesn't support void, which will be fixed in future swagger-parser release - // https://github.com/swagger-api/swagger-parser/pull/34 - completion(response: Response(response: response.response!, body: "" as! T), error: nil) - return - } + switch T.self { + case is NSData.Type: + validatedRequest.responseData({ (dataResponse) in + cleanupRequest() - completion(response: nil, error: NSError(domain: "localhost", code: 500, userInfo: ["reason": "unreacheable code"])) + if (dataResponse.result.isFailure) { + completion( + response: nil, + error: dataResponse.result.error + ) + return + } + + completion( + response: Response( + response: dataResponse.response!, + body: dataResponse.data as! T + ), + error: nil + ) + }) + default: + validatedRequest.responseJSON(options: .AllowFragments) { response in + cleanupRequest() + + if response.result.isFailure { + completion(response: nil, error: response.result.error) + return + } + + if () is T { + completion(response: Response(response: response.response!, body: () as! T), error: nil) + return + } + if let json: AnyObject = response.result.value { + let body = Decoders.decode(clazz: T.self, source: json) + completion(response: Response(response: response.response!, body: body), error: nil) + return + } else if "" is T { + // swagger-parser currently doesn't support void, which will be fixed in future swagger-parser release + // https://github.com/swagger-api/swagger-parser/pull/34 + completion(response: Response(response: response.response!, body: "" as! T), error: nil) + return + } + + completion(response: nil, error: NSError(domain: "localhost", code: 500, userInfo: ["reason": "unreacheable code"])) + } } } diff --git a/modules/swagger-codegen/src/main/resources/swift/Extensions.mustache b/modules/swagger-codegen/src/main/resources/swift/Extensions.mustache index 7fbfa50b28..27253b6d95 100644 --- a/modules/swagger-codegen/src/main/resources/swift/Extensions.mustache +++ b/modules/swagger-codegen/src/main/resources/swift/Extensions.mustache @@ -59,6 +59,11 @@ extension Dictionary: JSONEncodable { } } +extension NSData: JSONEncodable { + func encodeToJSON() -> AnyObject { + return self.base64EncodedStringWithOptions(NSDataBase64EncodingOptions()) + } +} private let dateFormatter: NSDateFormatter = { let fmt = NSDateFormatter() diff --git a/modules/swagger-codegen/src/main/resources/swift/Models.mustache b/modules/swagger-codegen/src/main/resources/swift/Models.mustache index 4e858493e2..a79bbdea07 100644 --- a/modules/swagger-codegen/src/main/resources/swift/Models.mustache +++ b/modules/swagger-codegen/src/main/resources/swift/Models.mustache @@ -68,6 +68,9 @@ class Decoders { if source is T { return source as! T } + if T.self is NSData.Type && source is String { + return NSData(base64EncodedString: source as! String, options: NSDataBase64DecodingOptions()) as! T + } let key = "\(T.self)" if let decoder = decoders[key] { diff --git a/modules/swagger-codegen/src/test/java/io/swagger/codegen/languages/SwiftCodegenTest.java b/modules/swagger-codegen/src/test/java/io/swagger/codegen/swift/SwiftCodegenTest.java similarity index 66% rename from modules/swagger-codegen/src/test/java/io/swagger/codegen/languages/SwiftCodegenTest.java rename to modules/swagger-codegen/src/test/java/io/swagger/codegen/swift/SwiftCodegenTest.java index 4f4508f78e..0fbfcf5efe 100644 --- a/modules/swagger-codegen/src/test/java/io/swagger/codegen/languages/SwiftCodegenTest.java +++ b/modules/swagger-codegen/src/test/java/io/swagger/codegen/swift/SwiftCodegenTest.java @@ -1,5 +1,12 @@ -package io.swagger.codegen.languages; +package io.swagger.codegen.swift; +import io.swagger.codegen.CodegenOperation; +import io.swagger.codegen.DefaultCodegen; +import io.swagger.codegen.InlineModelResolver; +import io.swagger.codegen.languages.SwiftCodegen; +import io.swagger.models.Operation; +import io.swagger.models.Swagger; +import io.swagger.parser.SwaggerParser; import org.testng.Assert; import org.testng.annotations.Test; @@ -42,6 +49,20 @@ public class SwiftCodegenTest { Assert.assertEquals(swiftCodegen.toSwiftyEnumName("entry_name"), "EntryName"); } + @Test(description = "returns NSData when response format is binary") + public void binaryDataTest() { + final Swagger model = new SwaggerParser().read("src/test/resources/2_0/binaryDataTest.json"); + final DefaultCodegen codegen = new SwiftCodegen(); + final String path = "/tests/binaryResponse"; + final Operation p = model.getPaths().get(path).getPost(); + final CodegenOperation op = codegen.fromOperation(path, "post", p, model.getDefinitions()); + + Assert.assertEquals(op.returnType, "NSData"); + Assert.assertEquals(op.bodyParam.dataType, "NSData"); + Assert.assertTrue(op.bodyParam.isBinary); + Assert.assertTrue(op.responses.get(0).isBinary); + } + @Test public void testDefaultPodAuthors() throws Exception { // Given diff --git a/modules/swagger-codegen/src/test/java/io/swagger/codegen/swift/SwiftModelTest.java b/modules/swagger-codegen/src/test/java/io/swagger/codegen/swift/SwiftModelTest.java index c925535403..c3d2d829c9 100644 --- a/modules/swagger-codegen/src/test/java/io/swagger/codegen/swift/SwiftModelTest.java +++ b/modules/swagger-codegen/src/test/java/io/swagger/codegen/swift/SwiftModelTest.java @@ -18,6 +18,8 @@ public class SwiftModelTest { .property("id", new LongProperty()) .property("name", new StringProperty()) .property("createdAt", new DateTimeProperty()) + .property("binary", new BinaryProperty()) + .property("byte", new ByteArrayProperty()) .property("uuid", new UUIDProperty()) .required("id") .required("name") @@ -28,7 +30,7 @@ public class SwiftModelTest { Assert.assertEquals(cm.name, "sample"); Assert.assertEquals(cm.classname, "Sample"); Assert.assertEquals(cm.description, "a sample model"); - Assert.assertEquals(cm.vars.size(), 4); + Assert.assertEquals(cm.vars.size(), 6); Assert.assertEquals(cm.discriminator,"test"); final CodegenProperty property1 = cm.vars.get(0); @@ -64,14 +66,34 @@ public class SwiftModelTest { Assert.assertTrue(property3.isNotContainer); final CodegenProperty property4 = cm.vars.get(3); - Assert.assertEquals(property4.baseName, "uuid"); - Assert.assertEquals(property4.datatype, "NSUUID"); - Assert.assertEquals(property4.name, "uuid"); + Assert.assertEquals(property4.baseName, "binary"); + Assert.assertEquals(property4.datatype, "NSData"); + Assert.assertEquals(property4.name, "binary"); Assert.assertNull(property4.defaultValue); - Assert.assertEquals(property4.baseType, "NSUUID"); - Assert.assertNull(property4.hasMore); + Assert.assertEquals(property4.baseType, "NSData"); + Assert.assertTrue(property4.hasMore); Assert.assertNull(property4.required); Assert.assertTrue(property4.isNotContainer); + + final CodegenProperty property5 = cm.vars.get(4); + Assert.assertEquals(property5.baseName, "byte"); + Assert.assertEquals(property5.datatype, "NSData"); + Assert.assertEquals(property5.name, "byte"); + Assert.assertNull(property5.defaultValue); + Assert.assertEquals(property5.baseType, "NSData"); + Assert.assertTrue(property5.hasMore); + Assert.assertNull(property5.required); + Assert.assertTrue(property5.isNotContainer); + + final CodegenProperty property6 = cm.vars.get(5); + Assert.assertEquals(property6.baseName, "uuid"); + Assert.assertEquals(property6.datatype, "NSUUID"); + Assert.assertEquals(property6.name, "uuid"); + Assert.assertNull(property6.defaultValue); + Assert.assertEquals(property6.baseType, "NSUUID"); + Assert.assertNull(property6.hasMore); + Assert.assertNull(property6.required); + Assert.assertTrue(property6.isNotContainer); } } diff --git a/samples/client/petstore/swift/default/PetstoreClient/Classes/Swaggers/AlamofireImplementations.swift b/samples/client/petstore/swift/default/PetstoreClient/Classes/Swaggers/AlamofireImplementations.swift index 0b153ad17d..cabf67567b 100644 --- a/samples/client/petstore/swift/default/PetstoreClient/Classes/Swaggers/AlamofireImplementations.swift +++ b/samples/client/petstore/swift/default/PetstoreClient/Classes/Swaggers/AlamofireImplementations.swift @@ -82,30 +82,59 @@ class AlamofireRequestBuilder: RequestBuilder { request.authenticate(usingCredential: credential) } - request.validate().responseJSON(options: .AllowFragments) { response in + let cleanupRequest = { managerStore.removeValueForKey(managerId) + } - if response.result.isFailure { - completion(response: nil, error: response.result.error) - return - } + let validatedRequest = request.validate() - if () is T { - completion(response: Response(response: response.response!, body: () as! T), error: nil) - return - } - if let json: AnyObject = response.result.value { - let body = Decoders.decode(clazz: T.self, source: json) - completion(response: Response(response: response.response!, body: body), error: nil) - return - } else if "" is T { - // swagger-parser currently doesn't support void, which will be fixed in future swagger-parser release - // https://github.com/swagger-api/swagger-parser/pull/34 - completion(response: Response(response: response.response!, body: "" as! T), error: nil) - return - } + switch T.self { + case is NSData.Type: + validatedRequest.responseData({ (dataResponse) in + cleanupRequest() - completion(response: nil, error: NSError(domain: "localhost", code: 500, userInfo: ["reason": "unreacheable code"])) + if (dataResponse.result.isFailure) { + completion( + response: nil, + error: dataResponse.result.error + ) + return + } + + completion( + response: Response( + response: dataResponse.response!, + body: dataResponse.data as! T + ), + error: nil + ) + }) + default: + validatedRequest.responseJSON(options: .AllowFragments) { response in + cleanupRequest() + + if response.result.isFailure { + completion(response: nil, error: response.result.error) + return + } + + if () is T { + completion(response: Response(response: response.response!, body: () as! T), error: nil) + return + } + if let json: AnyObject = response.result.value { + let body = Decoders.decode(clazz: T.self, source: json) + completion(response: Response(response: response.response!, body: body), error: nil) + return + } else if "" is T { + // swagger-parser currently doesn't support void, which will be fixed in future swagger-parser release + // https://github.com/swagger-api/swagger-parser/pull/34 + completion(response: Response(response: response.response!, body: "" as! T), error: nil) + return + } + + completion(response: nil, error: NSError(domain: "localhost", code: 500, userInfo: ["reason": "unreacheable code"])) + } } } diff --git a/samples/client/petstore/swift/default/PetstoreClient/Classes/Swaggers/Extensions.swift b/samples/client/petstore/swift/default/PetstoreClient/Classes/Swaggers/Extensions.swift index f93d41600f..c974cc40b3 100644 --- a/samples/client/petstore/swift/default/PetstoreClient/Classes/Swaggers/Extensions.swift +++ b/samples/client/petstore/swift/default/PetstoreClient/Classes/Swaggers/Extensions.swift @@ -58,6 +58,11 @@ extension Dictionary: JSONEncodable { } } +extension NSData: JSONEncodable { + func encodeToJSON() -> AnyObject { + return self.base64EncodedStringWithOptions(NSDataBase64EncodingOptions()) + } +} private let dateFormatter: NSDateFormatter = { let fmt = NSDateFormatter() diff --git a/samples/client/petstore/swift/default/PetstoreClient/Classes/Swaggers/Models.swift b/samples/client/petstore/swift/default/PetstoreClient/Classes/Swaggers/Models.swift index 15a835a974..519aa5cc78 100644 --- a/samples/client/petstore/swift/default/PetstoreClient/Classes/Swaggers/Models.swift +++ b/samples/client/petstore/swift/default/PetstoreClient/Classes/Swaggers/Models.swift @@ -68,6 +68,9 @@ class Decoders { if source is T { return source as! T } + if T.self is NSData.Type && source is String { + return NSData(base64EncodedString: source as! String, options: NSDataBase64DecodingOptions()) as! T + } let key = "\(T.self)" if let decoder = decoders[key] {