I'm not sure about this, but maybe allowing modification of the decoder options during decoding (inside the init(from:)
method) would solve this. Allowing this for all options would also address similar issues that might come up for the other options of JSONDecoder
.
Example
The custom decoding code would look somehow like this:
init(from decoder: Decoder) throws {
// decode things with the default key decoding strategy
// set key decoding strategy to the desired one, storing the old one
// decoding in this example the dictionary
// set strategy back to the old strategy
}
Implementation
- This could be implemented by either exposing
_JSONDecoder
andJSONDecoder._Options
publicly and makingoptions
on_JSONDecoder
a var. - or by (hypothetically) storing the options inside
userInfo
(currently, it is the other way around) at a key likeJSONDecoderOptions
that would be defined byJSONDecoder
and contained the_Options
struct as value. However, this is purely theoretical, becauseDecoder
hasuserInfo
declared only as asget
property. This approach also seems to turn around the sense ofuserInfo
a bit, because here it's also information from the user to the decoder and not information purely for the user. However, I see this way as the most elegant one, but requiring either source breaking changes or additional API, like aoptions: [OptionKey : Any] { get set }
property onDecoder
with default implementations returning[:]
and doing nothing. - Forward changes on the options (would need to be public, other option properties would be removed) of
JSONDecoder
to_JSONDecoder
. Every_JSONDecoder
would store a reference to theJSONDecoder
that created it and read those options or_Options
would explicitly use reference semantics, such that_JSONDecoder
andJSONDecoder
could use the same_Options
reference, both having ownoptions
properties. Making_Options
would do this, I guess. In general, in this case there could be a bit additional confusion why I would need to store theJSONDecoder
and access it in myinit(from:)
method somehow, if I get another decoder as argument anyway.
Alternative
This is a bit tricky alternative, that is already implementable today.
If one already made sure, that one is decoding from JSON, e.g. by checking a previously set key in userInfo
, one decodes a JSONValue
enum to get unevaluated information. Then one will convert this JSON
types consumable by JSONSerialization
, re-encode the unevaluated information and then pass this newly created JSON data to a new JSONDecoder
with the desired options (concretely, a different key decoding strategy) and decode the type (dictionary here) with this JSONDecoder
.
This might get a but easier with decoders providing unevaluated information directly, as discussed in New "Unevaluated" type for Decoder to allow later re-encoding of data with unknown structure, but allowing this has not been discussed now, as far as I know.
Because the re-encoding keys does not result in the same keys, as far as I can see, it is necessary to go over JSONSerialization
here, I guess. One can use JSONEncoder to, if the used JSON
implementation is Encodable
, but this is actually one stage more.