Search code examples
jsonswiftsubclassalamofireobjectmapper

Different types JSON file using ObjectMapper


I am using AlamofireObjectMapper to communicate with a backend server. The result of one of the requests is an array of items, which contain two values:

  • A "typeIdentifier" indicating which type of data the second value ("arbitraryData") is of
  • A "arbitraryData":
    • If "typeIdentifier" CONTAINS "X", arbitraryData is of type ArbitraryDataTypeX
    • If "typeIdentifier" CONTAINS "Y", arbitraryData is of type ArbitraryDataTypeY

The two ArbitraryDataType classes do not share any common ancestor (except Mappable). It could be even a primitive type, an array, an optional, etc.

How can I make AlamofireObjectMapper parse the "arbitraryData" field using the appropriate type.

See the following JSON file:

{
    "arrayOfItems": [
        {
            "typeIdentifier": "X",
            "arbitraryData":
                {
                    "value": "BLA",
                }
        },
        {
            "typeIdentifier": "Y",
            "arbitraryData":
                {
                    "anotherValue": "BLUBB",
                }
        }
    ]
}

My corresponding Swing file looks like the following:

class Item : Mapping {
    var typeIdentifier = "X"
    var arbitraryData: Mappable? = nil

    init?(_ map: Map) {
        self.init()
        mapping(map)
    }

    func mapping(map: Map) {
        typeIdentifier <- map["typeIdentifier"]

        // THIS LINE CONTAINS MY QUESTION: HOW CAN I TELL OBJECTMAPPER, THAT,
        // IF typeIdentifier CONTAINS "X", arbitraryData IS OF TYPE
        // ArbitraryDataTypeX, AND IF "Y" arbitraryData IS OF TYPE
        // ArbitraryDataTypeY?
        arbitraryData <- map["arbitraryData"]
    }
}

class ArbitraryDataTypeX : Mapping {
    var value = "BLA"

    init?(_ map: Map) {
        self.init()
        mapping(map)
    }

    func mapping(map: Map) {
        value <- map["value"]
    }
}

class ArbitraryDataTypeY : Mapping {
    var anotherValue = "BLUBB"

    init?(_ map: Map) {
        self.init()
        mapping(map)
    }

    func mapping(map: Map) {
        anotherValue <- map["anotherValue"]
    }
}

Background information: I am using AlamofireObjectMapper to communicate with a backend server. The result of one of the requests is an array of Item. The typeIdentifier-mechanism (infact it is a little bit more complex, but let's leave this out) is given by the backend and cannot be changed.


Solution

  • Ok, I found a solution (I don't know why I didn't see it from the beginning):

    // This is Item.map()
    func mapping(map: Map) {
        typeIdentifier <- map["typeIdentifier"]
    
        switch typeIdentifier {
        case "X":
            let x: X?
            x <- map["arbitraryData"]
            arbitraryData = x
        case "Y":
            let y: Y?
            y <- map["arbitraryData"]
            arbitraryData = y
        default:
            arbitraryData = nil
        }
    }