hkellaway / Gloss

[Deprecated] A shiny JSON parsing library in Swift :sparkles: Loved by many from 2015-2021
https://hkellaway.github.io/blog/2020/08/30/tale-of-third-parties
MIT License
1.62k stars 142 forks source link

Serialization of Superclass properties #165

Closed doncorsean closed 8 years ago

doncorsean commented 8 years ago

`

class A {

    var foo:String?

    public override func toJSON() -> JSON? {
        return jsonify([
            "foo" ~~> self.foo
            ])
    }
}

class B:A {

    var bar:String?

    public override func toJSON() -> JSON? {
        return jsonify([
            "bar" ~~> self.bar
            ])
    }
}

So If I do this...

let b = B() b.foo = "foo" b.bar = "bar"

let json = b.toJSON()

print(json)

I get: ["bar":"bar"]

I am forced to jsonify the foo property inherited by class A within class B. It would be great if the responsibility of serializing inherited properties was delegated to the superclasses. Thoughts?

hkellaway commented 8 years ago

i don't see that one could get around having to serialize the property of the superclass A - what B is doing with its override is saying, ignore As implementation and do this instead; it makes sense.

a more descriptive way of achieving the full JSON in class B might be something like:

override func toJSON() -> JSON? {
    guard
        let superJSON = super.toJSON(),
        var json = jsonify([ "bar" ~~> self.bar ]) else {
            return nil
    }

    json.add(superJSON) // `add` is a custom function that combines two dictionaries

    return json
}

the add function you see there combines two dictionaries (see the ExtensionDictionary.swift file in the Gloss library for an example of how one might implement that).

but the bigger issue i see is that this set up violates (my understanding of) the Liskov Substitution Principle - which says that a subclass should be substitutable for its superclass. in this setup, your application code would have to know it was using an instance of B in order to access the bar property, which means A and B are not substitutable. another way to phrase this is, whether we have a class of type A or of type B at runtime, we want calling toJSON on it to produce the same output. so, perhaps, a rethink of the models is due.

hope that helps!

doncorsean commented 8 years ago

So I've got a test working where super.toJSON() is merged with the result of jsonify. My problem is I have hundreds of generated classes which each require implementation of these initializer/toJSON methods. Seems like tons of boilerplate code for already known and defined properties within a class. Would be nice if Swift's "reflection" would allow us to skip this manual declaration of all the mapping if the structure of the JSON and property names were verbatim and we would only need to implement toJSON when one wanted to customize the serialization.