Environment
Digital Ocean Droplet
Ubuntu Linux 20.04
Swift 5.5.1
Additional Detail from JIRA
| | |
|------------------|-----------------|
|Votes | 0 |
|Component/s | |
|Labels | Bug |
|Assignee | None |
|Priority | Medium |
md5: c886bfe0eef50a04b68246dfd1b54ac3
Issue Description:
When using a dictionary that contains an array as a value, and it is empty but not nil, the encoder encodes it as if it was an array and not a dictionary.
Code to replicate:
// replication example
class Test : Codable {
init(){}
var id: UUID = UUID()
var data: [UUID:[String]] = [:]
}
if let encodedObject = try? JSONEncoder().encode(Test()) {
print("encoded json:\n\(String(data: encodedObject, encoding: .utf8)!)")
do {
let reformedObject = try JSONDecoder().decode(Test.self, from: encodedObject)
print("worked")
} catch {
print("failed")
print("json decode error: \(error)")
}
}
Output on MacOS 12.0.1:
encoded json:
{"id":"D320770C-0B69-4FC0-8854-3FE4A8F9EA3A","data":[]}
worked
Output on Ubuntu Linux 20.04:
encoded json:
{"data":{},"id":"0CA4125F-95DF-4D70-A6AD-3B661908FC29"}
failed
json decode error: typeMismatch(Swift.Array<Foundation.JSONValue>, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "data", intValue: nil)], debugDescription: "Expected to decode Array<JSONValue> but found a dictionary instead.", underlyingError: nil))
In reality both are wrong. MacOS accepts an Array where it should be a dictionary: And Linux Expects and array but encodes it correctly as a dictionary.
When the object is populated with data, the encoding/decoding works as expected:
Revised class for populated/working code:
class Test : Codable {
init(){}
var id: UUID = UUID()
var data: [UUID:[String]] = [UUID():["AnyOldDataCanGoHere"]]
}
MacOS output:
encoded json:
{"id":"81A41826-6F00-42D7-91AE-264E5983FE53","data":["F478B1A5-7CB9-4F3C-B8D1-41ADFBA83108",["AnyOldDataCanGoHere"]]}
worked
NOTE: Still outputting as an array and not a dictionary
Linux output:
encoded json:
{"id":"91DDC7F7-DF4D-4DFD-8616-BD59BB3E8902","data":["96293D09-2046-4918-8CD6-1A4082AB1242",["AnyOldDataCanGoHere"]]}
worked
Incorrect encoding (`[]` not `{}`), correct behaviour.
Additional debugging/research:
If we change the format of the property to
var data: [String:[String]] = [:]
, then this is the output from both platforms, and everything works as expected:
encoded json:
{"data":{},"id":"F1DAADFD-F836-4F42-8932-CE1596B583B9"}
worked
Environment
Digital Ocean Droplet Ubuntu Linux 20.04 Swift 5.5.1Additional Detail from JIRA
| | | |------------------|-----------------| |Votes | 0 | |Component/s | | |Labels | Bug | |Assignee | None | |Priority | Medium | md5: c886bfe0eef50a04b68246dfd1b54ac3Issue Description:
When using a dictionary that contains an array as a value, and it is empty but not nil, the encoder encodes it as if it was an array and not a dictionary.
Code to replicate:
Output on MacOS 12.0.1:
Output on Ubuntu Linux 20.04:
In reality both are wrong. MacOS accepts an Array where it should be a dictionary: And Linux Expects and array but encodes it correctly as a dictionary.
When the object is populated with data, the encoding/decoding works as expected:
Revised class for populated/working code:
MacOS output:
NOTE: Still outputting as an array and not a dictionary
Linux output:
Incorrect encoding (`[]` not `{}`), correct behaviour.
Additional debugging/research:
If we change the format of the property to
, then this is the output from both platforms, and everything works as expected:
This is similar in output to:
https://bugs.swift.org/browse/SR-5312
But different scenario, and setup. E.g. even with String keys the encoder uses '[ ]' and not '{ }'.