I'm currently getting JSON from a server that I don't have access to. The JSON I sometimes get will put this character \u0000
at the end of a String. As a result my decoding fails because this character just fails it.
I'm trying to debug this in Playground but I keep getting this error.
Expected hexadecimal code in braces after unicode escape
Here is some sample code to try out.
import UIKit
import Foundation
struct GroceryProduct: Codable {
var name: String
}
let json = """
{
"name": "Durian \u0000"
}
""".data(using: .utf8)!
let decoder = JSONDecoder()
let product = try decoder.decode(GroceryProduct.self, from: json)
print(product.name)
How do you deal with \u0000
from JSON? I have been looking at DataDecodingStrategy from the Apple documentation but I can't even test anything out because the Playground fails to even run.
Any direction or advice would be appreciated.
Here is some more setup code to tryout in your Playground or a real app.
{
"name": "Durian \u0000"
}
extension Bundle {
func decode<T: Decodable>(_ type: T.Type, from file: String, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .deferredToDate, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) -> T {
guard let url = self.url(forResource: file, withExtension: nil) else {
fatalError("Failed to locate \(file) in bundle.")
}
guard let data = try? Data(contentsOf: url) else {
fatalError("Failed to load \(file) from bundle.")
}
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .deferredToDate
decoder.keyDecodingStrategy = .useDefaultKeys
do {
return try decoder.decode(T.self, from: data)
} catch DecodingError.keyNotFound(let key, let context) {
fatalError("Failed to decode \(file) from bundle due to missing key '\(key.stringValue)' not found – \(context.debugDescription)")
} catch DecodingError.typeMismatch(_, let context) {
fatalError("Failed to decode \(file) from bundle due to type mismatch – \(context.debugDescription)")
} catch DecodingError.valueNotFound(let type, let context) {
fatalError("Failed to decode \(file) from bundle due to missing \(type) value – \(context.debugDescription)")
} catch DecodingError.dataCorrupted(_) {
fatalError("Failed to decode \(file) from bundle because it appears to be invalid JSON")
} catch {
fatalError("Failed to decode \(file) from bundle: \(error.localizedDescription)")
}
}
}
struct GroceryProduct: Codable {
var name: String
}
// Try running this and it won't work
let results = Bundle.main.decode(GroceryProduct.self, from: "test.json")
print(results.name)
You need to escape \u0000
characters first - this can be done before decoding:
guard let data = try? Data(contentsOf: url) else {
fatalError("Failed to load \(file) from bundle.")
}
let escaped = Data(String(data: data, encoding: .utf8)!.replacingOccurrences(of: "\0", with: "").utf8)
...
return try decoder.decode(T.self, from: escaped)
Note: force-unwrapping for simplicity only.
In Playground you can escape it with an additional \
(to make it work):
let json = """
{
"name": "Durian \\u0000"
}
""".data(using: .utf8)!
or replace it with \0
(to make it fail - behave like during the decoding):
let json = """
{
"name": "Durian \0"
}
""".data(using: .utf8)!