<div dir="ltr">(Added swift users as CC)</div><div class="gmail_extra"><br><div class="gmail_quote">2017-06-24 3:47 GMT+09:00 Masaki Haga <span dir="ltr">&lt;<a href="mailto:hgmsk1985@gmail.com" target="_blank">hgmsk1985@gmail.com</a>&gt;</span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">Hi Tony,<div><br></div><div>Got it. Thank you very much for taking time for this.</div></div><div class="HOEnZb"><div class="h5"><div class="gmail_extra"><br><div class="gmail_quote">2017-06-24 1:40 GMT+09:00 Tony Parker <span dir="ltr">&lt;<a href="mailto:anthony.parker@apple.com" target="_blank">anthony.parker@apple.com</a>&gt;</span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space">Hi Masaki,<div><br></div><div>Thanks for the additional info. I have a slightly different idea on how to approach this which I think will be more performant. Let me work on that and get back to you.</div><span class="m_7509852125003066325HOEnZb"><font color="#888888"><div><br></div></font></span><div><span class="m_7509852125003066325HOEnZb"><font color="#888888">- Tony</font></span><div><div class="m_7509852125003066325h5"><br><div><br><blockquote type="cite"><div>On Jun 22, 2017, at 7:51 PM, Masaki Haga &lt;<a href="mailto:hgmsk1985@gmail.com" target="_blank">hgmsk1985@gmail.com</a>&gt; wrote:</div><br class="m_7509852125003066325m_7729558900810834371Apple-interchange-newline"><div><div dir="ltr"><div>Hi Tony,</div><div><br></div><div>Thank you very much for replying. Let me clarify what I was saying.</div><div><br></div><div>Let’s say, we have a JSON like this:</div><div><br></div><div>{</div><div><span class="m_7509852125003066325m_7729558900810834371gmail-Apple-tab-span" style="white-space:pre-wrap">        </span>&quot;badge&quot;: 1,</div><div><span class="m_7509852125003066325m_7729558900810834371gmail-Apple-tab-span" style="white-space:pre-wrap">        </span>&quot;content_available&quot;: false,</div><div><span class="m_7509852125003066325m_7729558900810834371gmail-Apple-tab-span" style="white-space:pre-wrap">        </span>&quot;mutable_content&quot;: false</div><div>}</div><div><br></div><div>and to decode this JSON, we have to have a Codable model like below with custom CodingKeys enum:</div><div><br></div><div>struct APS: Codable {</div><div>    enum CodingKeys: String, CodingKey {</div><div>        case badge = &quot;badge&quot;</div><div>        case contentAvailable = &quot;content_available&quot;</div><div>        case mutableContent = &quot;mutable_content&quot;</div><div>    }</div><div>    </div><div>    var badge: Int</div><div>    var contentAvailable: Bool</div><div>    var mutableContent: Bool</div><div>}</div><div><br></div><div>This is a very small JSON so it is not hard to write this custom enum. However, it is very cumbersome to define this enum in all of the pre-existing models in our project to be able to decoded by Decodable and we rather prefer just to have a model something like this:</div><div><br></div><div>struct APS: Codable {</div><div>    var badge: Int</div><div>    var contentAvailable: Bool</div><div>    var mutableContent: Bool</div><div>}</div><div><br></div><div>To be able to decode this model with JSONDecoder, I wrote a JSON converter like this:</div><div><br></div><div>extension String {</div><div>    var camelcased: String {</div><div>        return self</div><div>            .components(separatedBy: &quot;_&quot;)</div><div>            .enumerated()</div><div>            .map { 0 == $0.offset ? $0.element : $0.element.capitalized }</div><div>            .joined()</div><div>    }</div><div>}</div><div>// This extension above was referenced from an article written in Japanese: <a href="http://qiita.com/takasek/items/77955948fe283758ee55" target="_blank">http://qiita.com/takasek/items<wbr>/77955948fe283758ee55</a></div><div><br></div><div>struct JSONCaseConverter {</div><div>    public static func process(_ JSONObject: Any) -&gt; Any {</div><div>        if var dict = JSONObject as? [String: Any] {</div><div>            for (key, value) in dict {</div><div>                dict[key.camelcased] = process(value)</div><div>                dict.removeValue(forKey: key)</div><div>            }</div><div>            return dict</div><div>        } else if let array = JSONObject as? [Any] {</div><div>            return array.map(process)</div><div>        } else {</div><div>            return JSONObject</div><div>        }</div><div>    }</div><div>}</div><div><br></div><div>Basically, this JSONCaseConverter go though all the keys in a JSON and convert the key from snake-case to camel-case so that the JSON can be decoded directly with the model without custom CodingKeys enum.</div><div><br></div><div>And then if we have a Data type JSON object (typically got from URLSession.dataTask) and want to do some processing like this and decode with JSONDecoder, we need to do:</div><div><br></div><div>1. Serialize Data object with JSONSerialization.jsonObject(w<wbr>ith:) and get Any type JSON Object </div><div>2. do some processing  to the Any type JSON Object</div><div>3. Serialize Any type Object with JSONSerialization.data(withJSO<wbr>NObject:)  and get Data type JSON Object back.</div><div>4. and then call JSONDecoder.decode(). </div><div><br></div><div>However, JSONSerialization.jsonObject(w<wbr>ith:) is called again in JSONDecoder.decode() implementation so there is a computational redundancy.</div><div><br></div><div>Because I have already seen several this camel-case vs snake-case discussion in some places including Swift Evolution, I guess not a small number of developers will take the similar apploach ( I understand automatic key renaming could be a unsafe operation and this is just my personal opinion).</div><div><br></div><div>Anyways, I was wondering if there is any way to opt-out the JSONSerialization.jsonObject(w<wbr>ith:) in JSONDecoder.decode(). And if not, is it a good idea to have one more API such as `decode&lt;T&gt;(_ type: T.Type, from JSONObject: Any)` which I think gives more flexibility to the API?</div><div><br></div><div>Regards,</div><div>- Masaki</div></div><div class="gmail_extra"><br><div class="gmail_quote">2017-06-23 8:01 GMT+09:00 Tony Parker <span dir="ltr">&lt;<a href="mailto:anthony.parker@apple.com" target="_blank">anthony.parker@apple.com</a>&gt;</span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space">Hi Masaki,<div><br></div><div>Do you mean that you are going through the JSON as a string value and changing the keys, then you want to pass this re-written JSON to the decoder?</div><div><br></div><div>- Tony<br><div><br><blockquote type="cite"><div><div class="m_7509852125003066325m_7729558900810834371h5"><div>On Jun 21, 2017, at 6:58 PM, Masaki Haga via swift-users &lt;<a href="mailto:swift-users@swift.org" target="_blank">swift-users@swift.org</a>&gt; wrote:</div><br class="m_7509852125003066325m_7729558900810834371m_7627660175874365207Apple-interchange-newline"></div></div><div><div><div class="m_7509852125003066325m_7729558900810834371h5"><div dir="ltr"><div style="font-size:14px">Hi Swift-Users,</div><div style="font-size:14px"><br></div><div style="font-size:14px">I was wondering if there is any way to decode JSON from Any type JSON Object using `JSONDecoder`, not from Data type object. </div><div style="font-size:14px"><br></div><div style="font-size:14px">Currently, `JSONDecoder` has only one decode function which decodes Data type object to `Decodable`. Inside the function, it serializes Data object to Any Type JSON Object using `JSONSerialization` and pass it into `_JSONDecoder(referencing:, options:)` (Refer JSONEncoder.swift#874).</div><div style="font-size:14px"><br></div><div style="font-size:14px">As discussed in some of other threads such as &quot;SE-0166: Swift Archival &amp; Serialization&quot;, the default implementation of JSONDecoder or Decodable protocol doesn’t allow to decode from one format to another format (such as snake-case to camel-case), we need to implement custom CodingKey enums. However, in our project, to parse the server API JSON response with snake-case, declaring custom CodingKey enums for all the pre-existing models is almost impossible and very inefficient, so I decided to covert all the JSON keys from snake-case to camel-case, and then pass it into `JSONDecoder.decode`. To achieve this, we need to convert the Data object resulted from `URLSession.task` to Any type JSON Object using `JSONSerialization`, do the conversion from snake-case to camel-case and then convert back to Data type and then pass to `JSONDecoder.decode` which looks very redundant because the function uses `JSONSerialization` inside of it as mentioned above. If there is a function like below, we can get rid of this redundant call of `JSONSerialization`.</div><div style="font-size:14px"><br></div><div style="font-size:14px">```</div><div style="font-size:14px">func decode&lt;T : Decodable&gt;(_ type: T.Type, from JSONObject: Any) throws -&gt; T</div><div style="font-size:14px">```</div><div style="font-size:14px"><br></div><div style="font-size:14px">Sorry if I am misunderstanding the new API but is there any way to decode `Decodable` directly from Any type JSON Object?</div><div style="font-size:14px"><br></div><div style="font-size:14px">If not, I think adding the function aforementioned and giving an ability to opt-out this JSON serialization call would give more flexibility to the API in my humble opinion.</div><div style="font-size:14px"><br></div><div style="font-size:14px">Thank you for reading.</div><div style="font-size:14px"><br></div><div style="font-size:14px">All the best,</div><div style="font-size:14px">- Masaki</div></div></div></div>
______________________________<wbr>_________________<br>swift-users mailing list<br><a href="mailto:swift-users@swift.org" target="_blank">swift-users@swift.org</a><br><a href="https://lists.swift.org/mailman/listinfo/swift-users" target="_blank">https://lists.swift.org/mailma<wbr>n/listinfo/swift-users</a><br></div></blockquote></div><br></div></div></blockquote></div><br></div>
</div></blockquote></div><br></div></div></div></div></blockquote></div><br></div>
</div></div></blockquote></div><br></div>