I understand the observed behavior and why it happens. My point is from a User POV wrapping a property shouldn't break decoding.
My concern with that is it's not done by Decodable, it's done by the implementation. I believe a custom version could already do this if desired, (besides the fact that it may break things). I don't think trying to force every Decoder implementation to use a specific approach is good solution.
I actually find the problem of property-wrapped optional values not being decodable from omitted keys to be satisfactorily addressed by the forthcoming property wrapper composition feature and a property wrapper like @Omittable whose only purpose is to trigger a decoder overload that populates it’s wrapped value with nil if the respective key is not found. The nice thing about this is that you no longer have ambiguity by default (that an optional property can be decoded from null or from an omitted key/value).
[EDIT] I am not talking about overriding init(from: Decoder)
Another property wrapper doesn't solve the feature by itself (See @gwendal.roue's example). Changing Decoder would work, but a believe any change would require support be added to each individual decoder implementation. That would be a source breaking change which is not ideal.
Since code generation is already being used for Codable conformance and Property Wrapper I don't see I reason why it can't be used to solve this problem as well.
That works! I didn't realize specialized functions diverted code from outside your own code...makes sense though. Thank you! I would still like a more "official" way to handle this, but this at least gives me the workaround I need!
This workaround - could it be used to wrap an optional Bool property, so that it's serialized in JSON as an Int (1=true, 0=false or null if nil or missing) and decoded as a Bool?
I have a case where an external API, over which I have no control, returns a property as a JSON number (1 or 0) meaning true or false, and I want to treat it as an optional Bool in my Codable Swift class (I'm using a class, not a struct, as I'm integrating Codable with CoreData classes).
In Kotlin, I achieved this very easily using GSON's @JsonAdapter annotation;
data class MyDataClass ( @JsonAdapter(CustomTypeAdapterFactory::class) @SerializedName("my_optional_bool") val myOptionalBool: Boolean?
)
But I'm not sure of the best way to achieve this in Swift. I have a similar issue, where I need to encode a Date into a custom JSON format, that I would like to achieve in a similar way.
Customizing Codable with PropertyWrappers seems to me like the closest thing I've seen so far, but it would be good to get guidance on whether this is the case.
Yes, it should be possible. I'm planning on pushing the nullable wrappers this weekend to make it easier, but the non-null version would be something like this:
Thanks for this. Your library is excellent, exactly the kind of thing I was looking for! I look forward to the update to nullable wrappers.
Another useful concept in my Kotlin-based data classes, that use Android's Room library, is the @Expose annotation - ie. that can be used for deciding which properties get serialized to JSON.
At the moment, I'm planning to handle this in Swift by omitting CodingKeys for the properties I don't want serialized (I understand this is currently the standard way to do this) - but I find this a bit ugly and non-intuitive. It seems to me it would be better handled by property wrappers, either by exposing or ignoring the property where it's declared, e.g.;
struct MyType: Codable {
@CodingUses<IntAsBoolStaticCoder>
var myBool: Bool
@Ignore
var myStringNotToBeSerialized: String
}
Whether this should be handled by a library like yours, or whether this should be doable in standard Swift as part of customizing Codable, I don't know - it's just something I'd like to be able to do, along with using a GSON-like @SerializedName 'annotation' instead of, again, defining it within the CodingKeys enum, although I understand a property can only have one property wrapper (?), so I guess it's not doable to use multiple property wrappers to achieve something like;
struct MyType: Codable {
@SerializedName("my_date") @SecondsSince1970DateCoding
var myDate: Date
}
I wonder if it's possible for a property wrapper to have a generic parameter for another PW so the outer one channels both. Hmm, but how would initializations work (if the inner one needs to)?
That's what composition is supposed to handle (see proposal) but as it's missing from Swift 5.1 even though the proposal says "implemented", I'm unsure when/if that's coming.
That's not too surprising. There are a lot of Swift features that don't work well with Core Data. That's why I tend to use separate models for the Codable part of a codebase.
@GetSwifty have you looked further into the @CodingKey("first-name") syntax? I'd be interested in this for decoding JSON that does not exactly match my codable struct.
Additionally, though this is more out of your proposal's realm, it would be interesting if we could define multiple decoding strategies so that we could decode our objects from different JSON sources for example. My use case is I have one model that I'd like to decode from some seed data and then decode the same model from a different api.