diff --git a/Sources/CodableTransform.swift b/Sources/CodableTransform.swift index 4cb72d55..29d38a8d 100644 --- a/Sources/CodableTransform.swift +++ b/Sources/CodableTransform.swift @@ -37,24 +37,21 @@ open class CodableTransform: TransformType { public init() {} open func transformFromJSON(_ value: Any?) -> Object? { - var _data: Data? = nil - switch value { - case let dict as [String : Any]: - _data = try? JSONSerialization.data(withJSONObject: dict, options: []) - case let array as [[String : Any]]: - _data = try? JSONSerialization.data(withJSONObject: array, options: []) - default: - _data = nil - } - guard let data = _data else { return nil } - - do { - let decoder = JSONDecoder() - let item = try decoder.decode(T.self, from: data) - return item - } catch { - return nil - } + guard let item = value else { + return nil + } + + if JSONSerialization.isValidJSONObject(item) { + guard let data = try? JSONSerialization.data(withJSONObject: item, options: []) else { + return nil + } + return try? JSONDecoder().decode(T.self, from: data) + } else { + guard let data = try? JSONSerialization.data(withJSONObject: ["value": item], options: []) else { + return nil + } + return try? JSONDecoder().decode(DecodableWrapper.self, from: data).value + } } open func transformToJSON(_ value: T?) -> JSON? { @@ -71,3 +68,7 @@ open class CodableTransform: TransformType { } } } + +private struct DecodableWrapper: Decodable { + let value: T +} diff --git a/Tests/ObjectMapperTests/CodableTests.swift b/Tests/ObjectMapperTests/CodableTests.swift index 8eb32296..adc5ba4d 100644 --- a/Tests/ObjectMapperTests/CodableTests.swift +++ b/Tests/ObjectMapperTests/CodableTests.swift @@ -32,49 +32,74 @@ import ObjectMapper class CodableTests: XCTestCase { - override func setUp() { - super.setUp() - // Put setup code here. This method is called before the invocation of each test method in the class. + func testSingleValueCodableTransform() { + let boolJSON = ["value": ["single_value": true]] + let boolObject = try? Mapper>().map(JSON: boolJSON) + XCTAssertEqual(true, boolObject?.value) + + let intJSON = ["value": ["single_value": 1]] + let intObject = try? Mapper>().map(JSON: intJSON) + XCTAssertEqual(1, intObject?.value) + + let stringJSON = ["value": ["single_value": "hello object mapper"]] + let stringObject = try? Mapper>().map(JSON: stringJSON) + XCTAssertEqual("hello object mapper", stringObject?.value) } - override func tearDown() { - // Put teardown code here. This method is called after the invocation of each test method in the class. - super.tearDown() + func testArrayValueCodableTransform() { + let boolArrayJSON = ["value": ["array_value": [false, false, true, true]]] + let boolArrayObject = try? Mapper>().map(JSON: boolArrayJSON) + XCTAssertEqual([false, false, true, true], boolArrayObject?.value) + + let intArrayJSON = ["value": ["array_value": [1, 2, 3, 4]]] + let intArrayObject = try? Mapper>().map(JSON: intArrayJSON) + XCTAssertEqual([1, 2, 3, 4], intArrayObject?.value) + + let stringArrayJSON = ["value": ["array_value": ["hello", "안녕", "nice to meet ypu", "만나서 반가워"]]] + let stringArrayObject = try? Mapper>().map(JSON: stringArrayJSON) + XCTAssertEqual(["hello", "안녕", "nice to meet ypu", "만나서 반가워"], stringArrayObject?.value) } func testCodableTransform() { - let value: [String: Any] = [ "one": "1", "two": 2, "three": true ] - let JSON: [String: Any] = [ "value": value, "array_value": [value, value]] - - let mapper = Mapper() + let value: [String: Any] = ["one": "1", "two": 2, "three": true] + let json: [String: Any] = ["value": value, "array_value": [value, value]] - let object: ImmutableMappableObject! = mapper.map(JSON: JSON) + let object = try? Mapper().map(JSON: json) XCTAssertNotNil(object) - XCTAssertNil(object.nilValue) // without transform this is nil - XCTAssertNotNil(object.value) - XCTAssertNotNil(object.value?.one) - XCTAssertNotNil(object.value?.two) - XCTAssertNotNil(object.value?.three) - XCTAssertNotNil(object.arrayValue) + XCTAssertNil(object?.nilValue) // without transform this is nil + XCTAssertNotNil(object?.value) + XCTAssertNotNil(object?.value?.one) + XCTAssertNotNil(object?.value?.two) + XCTAssertNotNil(object?.value?.three) + XCTAssertNotNil(object?.arrayValue) } } -class ImmutableMappableObject: ImmutableMappable { +class SingleMappableObject: ImmutableMappable { + let value: T - var value: CodableModel? - var arrayValue: [CodableModel]? - var nilValue: CodableModel? + required init(map: Map) throws { + self.value = try map.value("value.single_value", using: CodableTransform()) + } +} + +class ArrayMappableObject: ImmutableMappable { + let value: [T] required init(map: Map) throws { - nilValue = try? map.value("value") - value = try? map.value("value", using: CodableTransform()) - arrayValue = try? map.value("array_value", using: CodableTransform<[CodableModel]>()) + self.value = try map.value("value.array_value", using: CodableTransform()) } +} - func mapping(map: Map) { - nilValue <- map["value"] - value <- (map["value"], using: CodableTransform()) - arrayValue <- (map["array_value"], using: CodableTransform<[CodableModel]>()) +class MappableObject: ImmutableMappable { + let value: CodableModel? + let arrayValue: [CodableModel]? + let nilValue: CodableModel? + + required init(map: Map) throws { + self.nilValue = try? map.value("value") + self.value = try? map.value("value", using: CodableTransform()) + self.arrayValue = try? map.value("array_value", using: CodableTransform<[CodableModel]>()) } }