aronbalog / Vox

Swift JSON:API client framework
http://jsonapi.org
MIT License
46 stars 19 forks source link

Relationships missing on deserialization #23

Open nbonatsakis opened 5 years ago

nbonatsakis commented 5 years ago

I'm not sure if this is a bug or if it's an issue with how I'm using the lib, but I can't seem to get related objects to populate correctly.

Given the following JSON:

{
    "data": [
        {
            "attributes": {
                "arrival_time": "2019-01-02T09:27:37-05:00",
                "departure_time": "2019-01-02T09:27:37-05:00",
                "direction_id": 1,
                "schedule_relationship": null,
                "status": null,
                "stop_sequence": 3
            },
            "id": "prediction-39288223-2844-3",
            "relationships": {
                "route": {
                    "data": {
                        "id": "93",
                        "type": "route"
                    }
                },
                "stop": {
                    "data": {
                        "id": "2844",
                        "type": "stop"
                    }
                },
                "trip": {
                    "data": {
                        "id": "39288223",
                        "type": "trip"
                    }
                }
            },
            "type": "prediction"
        },
        {
            "attributes": {
                "arrival_time": "2019-01-02T09:41:32-05:00",
                "departure_time": "2019-01-02T09:41:32-05:00",
                "direction_id": 1,
                "schedule_relationship": null,
                "status": null,
                "stop_sequence": 3
            },
            "id": "prediction-39288313-2844-3",
            "relationships": {
                "route": {
                    "data": {
                        "id": "93",
                        "type": "route"
                    }
                },
                "stop": {
                    "data": {
                        "id": "2844",
                        "type": "stop"
                    }
                },
                "trip": {
                    "data": {
                        "id": "39288313",
                        "type": "trip"
                    }
                }
            },
            "type": "prediction"
        },
        {
            "attributes": {
                "arrival_time": "2019-01-02T09:56:32-05:00",
                "departure_time": "2019-01-02T09:56:32-05:00",
                "direction_id": 1,
                "schedule_relationship": null,
                "status": null,
                "stop_sequence": 3
            },
            "id": "prediction-39288212-2844-3",
            "relationships": {
                "route": {
                    "data": {
                        "id": "93",
                        "type": "route"
                    }
                },
                "stop": {
                    "data": {
                        "id": "2844",
                        "type": "stop"
                    }
                },
                "trip": {
                    "data": {
                        "id": "39288212",
                        "type": "trip"
                    }
                }
            },
            "type": "prediction"
        },
        {
            "attributes": {
                "arrival_time": "2019-01-02T10:14:11-05:00",
                "departure_time": "2019-01-02T10:14:11-05:00",
                "direction_id": 1,
                "schedule_relationship": null,
                "status": null,
                "stop_sequence": 3
            },
            "id": "prediction-39288292-2844-3",
            "relationships": {
                "route": {
                    "data": {
                        "id": "93",
                        "type": "route"
                    }
                },
                "stop": {
                    "data": {
                        "id": "2844",
                        "type": "stop"
                    }
                },
                "trip": {
                    "data": {
                        "id": "39288292",
                        "type": "trip"
                    }
                }
            },
            "type": "prediction"
        }
    ],
    "included": [
        {
            "attributes": {
                "color": "FFC72C",
                "description": "Local Bus",
                "direction_destinations": [
                    "Sullivan",
                    "Downtown Boston"
                ],
                "direction_names": [
                    "Outbound",
                    "Inbound"
                ],
                "long_name": "Sullivan - Downtown Boston",
                "short_name": "93",
                "sort_order": 9300,
                "text_color": "000000",
                "type": 3
            },
            "id": "93",
            "links": {
                "self": "/routes/93"
            },
            "type": "route"
        }
    ],
    "jsonapi": {
        "version": "1.0"
    }
}

And these resource classes:

class MBTAPrediction: Resource {

    @objc dynamic var arrivalTime: String?
    @objc dynamic var route: MBTARoute?

    override static var resourceType: String {
        return "prediction"
    }

    override class var codingKeys: [String : String] {
        return [
            "arrivalTime": "arrival_time"
        ]
    }

}

class MBTARoute: Resource {

    @objc dynamic var long_name: String?
    @objc dynamic var short_name: String?

    override static var resourceType: String {
        return "route"
    }

}

The following code fails because the related route object is nil.

        guard let url = Bundle.main.url(forResource: "mbta_predictions", withExtension: "json"),
            let data = try? Data(contentsOf: url) else {
                fatalError()
        }

        let deserializer = Deserializer.Collection<MBTAPrediction>()
        do {
            let document = try deserializer.deserialize(data: data)
            let predictions = document.data
            let routeDesc = predictions?.first?.route?.long_name
            // routeDesc should not be nil
        } catch {
            NSLog("Error deserializing MBTA response: \(error)")
        }

@aronbalog I found that if I put a break point inside of the ResourcePool where each resource is added and step through slowly, it makes the code work. So I think this maybe some sort of async race condition.

If I'm just doing something wrong, please let me know. Thanks!

aronbalog commented 5 years ago

@nbonatsakis Until I find appropriate solution, I suggest that you always retain Document<T> object. Removing this object from memory will cause unexpected side-effects at this moment. I'm having few solutions on my mind. Stay tuned.

ZahraAsgharzadeh commented 5 years ago

@nbonatsakis Until I find appropriate solution, I suggest that you always retain Document<T> object. Removing this object from memory will cause unexpected side-effects at this moment. I'm having few solutions on my mind. Stay tuned.

Hi , We're waiting for you to push update and fix this holy bug 😑

ZahraAsgharzadeh commented 5 years ago

I am still waiting ... there is no library for json api and I am in force to use your library , please post an update and solve this bug

deszip commented 4 years ago

@aronbalog we are using your library on a couple of real world projects. Would be great if you can share your thoughts on memory management for documents and high level description of whats wrong with them. I appreciate your work and can spend some time to build a fix.