您可以将子 JSON 对象解码为其字符串表示形式而不是具体类型吗?

Posted

技术标签:

【中文标题】您可以将子 JSON 对象解码为其字符串表示形式而不是具体类型吗?【英文标题】:Can you decode a child JSON object into its string representation instead of a concrete type? 【发布时间】:2020-01-23 04:49:05 【问题描述】:

好的,问一个类似于我前几天发布的this one 的问题。这里的区别是我想知道子对象的 json 是否可以作为 JSON 本身的转义字符串读入,而不是被解码。

考虑一下这个 json...


    "value" : "SomeValue",
    "child" : 
        "prop1" : "Value1",
        "prop2" : "Value2"
    

您可以毫无问题地将其解码为这些类...

class Wrapper : Codable 
    let value : String
    let child : ChildObject


class ChildObject : Codable 
    let prop1 : String
    let prop2 : String

我想知道是否有可能编写一个自定义解码器,让我将其解码成这个......

class Wrapper : Codable 
    let value : String
    let child : String  <-- Note: String

...并让 Wrapper.child 等于这个...

// Wrapper.child holds a string containing the escaped, raw JSON
Wrapper.child == "\"prop1\":\"Value1\",\"prop2\":\"Value2\""

到目前为止,我发现的唯一解决方案是将其显式解码为 AnyCodable(在 GitHub 上 here)之类的东西,这是一个美化的匿名编码实现,然后将其重新序列化回 JSON,然后再将其分配给初始化程序中的实际属性。看起来有点矫枉过正,但确实有效。

public init(from decoder: Decoder) throws 

    // Get the container for the CodingKeys
    let container = try decoder.container(keyedBy: CodingKeys.self)

    // Set 'value' directly as a string
    value = try container.decode(String.self, forKey: .value)

    // For 'child', Decode to an anonymous codable type,
    // Re-serialize that codable type back to JSON data
    // Convert that JSON data into a string, using that to set 'child'

    // decode an type-erased Codable object
    let anyCodable = try container.decode(AnyCodable.self, forKey: .child)

    // Reencode it back to JSON
    let encoder = JSONEncoder()
    let childJsonData = try encoder.encode(anyCodable)

    // Set that JSON on the object's string property
    child = String(data:childJsonData, encoding:.utf8)!

解码对我来说只是感觉很“臭”,只是再次重新编码。希望有一种方法可以在没有额外步骤的情况下做到这一点。

【问题讨论】:

解决方案 smells 与您的要求一样非常规 ????。你必须重新编码这些东西。 Codable没有其他办法 我同意@vadian 问题出在解码的地方,无法知道具体的类型是什么。出于所有意图和目的,它只是一个将被交给其他地方的桶。我最初正在与后端团队合作,看看他们是否可以在那里将其编码为字符串,但他们说这会破坏其他系统,所以我正在尝试寻找替代方案。 告诉后端团队发送一个密钥type以及字典,以便能够识别具体类型。发送不可预测的 JSON 是非常糟糕的做法。 他们已经这样做了。问题是这些具体类型是在完全独立的模块中定义的,并且没有办法将它们传递给解码器。相信我,我知道这不是最优的,但可以把它想象成通过 HTTP 发送它。它不知道具体的类型。接收器可以。同样在这里。第一次解码的地方不是使用站点。这只是把它送到那里。那部分确实知道具体的类型,它将在那里被解码。把它想象成 UPS。他们不知道甚至不在乎盒子里有一件衬衫或一架无人机。他们只是把盒子拿到它要去的地方。 【参考方案1】:

您正在寻找一种替代解决方案,而下面这个是替代解决方案。

在 ChildObject 类型上实现 CustomStringConvertible。

class ChildObject : Codable, CustomStringConvertible 
    let prop1 : String
    let prop2 : String

    var description: String 
        return "\(prop1) --- \(prop2)"
    

然后调用一个描述 getter

child = childJsonData.description

【讨论】:

以上是关于您可以将子 JSON 对象解码为其字符串表示形式而不是具体类型吗?的主要内容,如果未能解决你的问题,请参考以下文章

Java Gson 实现 Json 数据的生成与解析

python json形式的字符串 解码还原为json

深入理解ajax系列第三篇

网络安全之反序列化漏洞分析

在 swift 4 和 Xcode 9 中解码 ExpandableTableView 的嵌套 json 数组

使用 circe 在 Scala 中 JSON 将嵌套字段解码为 Map[String, String]