Merge pull request #3266 from ButterflyNetwork/swift-binary

[Swift] Handle binary data types
This commit is contained in:
wing328 2016-07-19 23:19:01 +08:00 committed by GitHub
commit 7fbb499ad1
10 changed files with 174 additions and 51 deletions

View File

@ -703,6 +703,8 @@ public class ObjcClientCodegen extends DefaultCodegen implements CodegenConfig {
example = "2013-10-20T19:20:30+01:00"; example = "2013-10-20T19:20:30+01:00";
} }
example = "@\"" + escapeText(example) + "\""; example = "@\"" + escapeText(example) + "\"";
} else if ("NSData".equalsIgnoreCase(type)) {
example = "1234";
} else if (!languageSpecificPrimitives.contains(type)) { } else if (!languageSpecificPrimitives.contains(type)) {
// type is a model class, e.g. User // type is a model class, e.g. User
type = type.replace("*", ""); type = type.replace("*", "");

View File

@ -87,6 +87,7 @@ public class SwiftCodegen extends DefaultCodegen implements CodegenConfig {
); );
defaultIncludes = new HashSet<String>( defaultIncludes = new HashSet<String>(
Arrays.asList( Arrays.asList(
"NSData",
"NSDate", "NSDate",
"NSURL", // for file "NSURL", // for file
"NSUUID", "NSUUID",
@ -129,10 +130,8 @@ public class SwiftCodegen extends DefaultCodegen implements CodegenConfig {
typeMapping.put("double", "Double"); typeMapping.put("double", "Double");
typeMapping.put("object", "AnyObject"); typeMapping.put("object", "AnyObject");
typeMapping.put("file", "NSURL"); typeMapping.put("file", "NSURL");
//TODO binary should be mapped to byte array typeMapping.put("binary", "NSData");
// mapped to String as a workaround typeMapping.put("ByteArray", "NSData");
typeMapping.put("binary", "String");
typeMapping.put("ByteArray", "String");
typeMapping.put("UUID", "NSUUID"); typeMapping.put("UUID", "NSUUID");
importMapping = new HashMap<String, String>(); importMapping = new HashMap<String, String>();
@ -258,6 +257,11 @@ public class SwiftCodegen extends DefaultCodegen implements CodegenConfig {
return toModelName(type); return toModelName(type);
} }
@Override
public boolean isDataTypeBinary(final String dataType) {
return dataType != null && dataType.equals("NSData");
}
/** /**
* Output the proper model name (capitalized) * Output the proper model name (capitalized)
* *

View File

@ -82,30 +82,59 @@ class AlamofireRequestBuilder<T>: RequestBuilder<T> {
request.authenticate(usingCredential: credential) request.authenticate(usingCredential: credential)
} }
request.validate().responseJSON(options: .AllowFragments) { response in let cleanupRequest = {
managerStore.removeValueForKey(managerId) managerStore.removeValueForKey(managerId)
}
if response.result.isFailure { let validatedRequest = request.validate()
completion(response: nil, error: response.result.error)
return
}
if () is T { switch T.self {
completion(response: Response(response: response.response!, body: () as! T), error: nil) case is NSData.Type:
return validatedRequest.responseData({ (dataResponse) in
} cleanupRequest()
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"])) 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"]))
}
} }
} }

View File

@ -59,6 +59,11 @@ extension Dictionary: JSONEncodable {
} }
} }
extension NSData: JSONEncodable {
func encodeToJSON() -> AnyObject {
return self.base64EncodedStringWithOptions(NSDataBase64EncodingOptions())
}
}
private let dateFormatter: NSDateFormatter = { private let dateFormatter: NSDateFormatter = {
let fmt = NSDateFormatter() let fmt = NSDateFormatter()

View File

@ -68,6 +68,9 @@ class Decoders {
if source is T { if source is T {
return source as! 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)" let key = "\(T.self)"
if let decoder = decoders[key] { if let decoder = decoders[key] {

View File

@ -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.Assert;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -42,6 +49,20 @@ public class SwiftCodegenTest {
Assert.assertEquals(swiftCodegen.toSwiftyEnumName("entry_name"), "EntryName"); 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 @Test
public void testDefaultPodAuthors() throws Exception { public void testDefaultPodAuthors() throws Exception {
// Given // Given

View File

@ -18,6 +18,8 @@ public class SwiftModelTest {
.property("id", new LongProperty()) .property("id", new LongProperty())
.property("name", new StringProperty()) .property("name", new StringProperty())
.property("createdAt", new DateTimeProperty()) .property("createdAt", new DateTimeProperty())
.property("binary", new BinaryProperty())
.property("byte", new ByteArrayProperty())
.property("uuid", new UUIDProperty()) .property("uuid", new UUIDProperty())
.required("id") .required("id")
.required("name") .required("name")
@ -28,7 +30,7 @@ public class SwiftModelTest {
Assert.assertEquals(cm.name, "sample"); Assert.assertEquals(cm.name, "sample");
Assert.assertEquals(cm.classname, "Sample"); Assert.assertEquals(cm.classname, "Sample");
Assert.assertEquals(cm.description, "a sample model"); Assert.assertEquals(cm.description, "a sample model");
Assert.assertEquals(cm.vars.size(), 4); Assert.assertEquals(cm.vars.size(), 6);
Assert.assertEquals(cm.discriminator,"test"); Assert.assertEquals(cm.discriminator,"test");
final CodegenProperty property1 = cm.vars.get(0); final CodegenProperty property1 = cm.vars.get(0);
@ -64,14 +66,34 @@ public class SwiftModelTest {
Assert.assertTrue(property3.isNotContainer); Assert.assertTrue(property3.isNotContainer);
final CodegenProperty property4 = cm.vars.get(3); final CodegenProperty property4 = cm.vars.get(3);
Assert.assertEquals(property4.baseName, "uuid"); Assert.assertEquals(property4.baseName, "binary");
Assert.assertEquals(property4.datatype, "NSUUID"); Assert.assertEquals(property4.datatype, "NSData");
Assert.assertEquals(property4.name, "uuid"); Assert.assertEquals(property4.name, "binary");
Assert.assertNull(property4.defaultValue); Assert.assertNull(property4.defaultValue);
Assert.assertEquals(property4.baseType, "NSUUID"); Assert.assertEquals(property4.baseType, "NSData");
Assert.assertNull(property4.hasMore); Assert.assertTrue(property4.hasMore);
Assert.assertNull(property4.required); Assert.assertNull(property4.required);
Assert.assertTrue(property4.isNotContainer); 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);
} }
} }

View File

@ -82,30 +82,59 @@ class AlamofireRequestBuilder<T>: RequestBuilder<T> {
request.authenticate(usingCredential: credential) request.authenticate(usingCredential: credential)
} }
request.validate().responseJSON(options: .AllowFragments) { response in let cleanupRequest = {
managerStore.removeValueForKey(managerId) managerStore.removeValueForKey(managerId)
}
if response.result.isFailure { let validatedRequest = request.validate()
completion(response: nil, error: response.result.error)
return
}
if () is T { switch T.self {
completion(response: Response(response: response.response!, body: () as! T), error: nil) case is NSData.Type:
return validatedRequest.responseData({ (dataResponse) in
} cleanupRequest()
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"])) 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"]))
}
} }
} }

View File

@ -58,6 +58,11 @@ extension Dictionary: JSONEncodable {
} }
} }
extension NSData: JSONEncodable {
func encodeToJSON() -> AnyObject {
return self.base64EncodedStringWithOptions(NSDataBase64EncodingOptions())
}
}
private let dateFormatter: NSDateFormatter = { private let dateFormatter: NSDateFormatter = {
let fmt = NSDateFormatter() let fmt = NSDateFormatter()

View File

@ -68,6 +68,9 @@ class Decoders {
if source is T { if source is T {
return source as! 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)" let key = "\(T.self)"
if let decoder = decoders[key] { if let decoder = decoders[key] {