json - 执行自定义解码后解码剩余的 JSON

标签 json go

我有一个 JSON 对象,其中包含一个接口(interface)的实现。我正在尝试采用该 JSON 并将其编码到一个结构中,同时创建接口(interface)的实现。

我已经设法让它通过自定义 JSON 解码函数实现接口(interface),但是我正在努力拼凑如何然后编码其余字段

我在 Go playground 中创建了一个示例

https://play.golang.org/p/ztF7H7etdjM

传递到我的应用程序中的 JSON 是

{

   "address":"1FYuJ4MsVmpzPoFJ6svJMJfygn91Eubid9",
   "nonce":13,
   "network_id":"qadre.demo.balance",
   "challenge":"f2b19e71876c087e681fc092ea3a34d5680bbfe772e40883563e1d5513bb593f",
   "type":"verifying_key",
   "verifying_key":{
      "verifying_key":"3b6a27bcceb6a42d62a3a8d02a6f0d73653215771de243a63ac048a18b59da29",
      "fqdn":"huski.service.key"
   },
   "signature":"a3bf8ee202a508d5a5632f50b140b70b7095d8836493dc7ac4159f6f3350280078b3a58b2162a240bc8c7485894554976a9c7b5d279d3f5bf49fec950f024e02",
   "fqdn":"huski.service.SingleKeyProof"
}

我尝试执行 json.Unmarshal 并为剩余字段传入一个新结构,但它似乎使我陷入无限循环,我的应用程序挂起然后崩溃

到目前为止我想出的最好的解决方案是将 JSON 编码到一个 `map[string]interface{} 中并分别处理每个字段,虽然这感觉很笨重

var m map[string]interface{}
if err := json.Unmarshal(data, &m); err != nil {
    return err
}

ad, ok := m["address"]
if ok {
    s.Address = ad.(string)
}
fqdn, ok := m["fqdn"]
if ok {
    s.FQDN = fqdn.(string)
}
n, ok := m["nonce"]
if ok {
    s.Nonce = int64(n.(float64))
}
c, ok := m["challenge"]
if ok {
    s.Challenge = []byte(c.(string))
}
network, ok := m["network_id"]
if ok {
    s.NetworkID = network.(string)
}
sig, ok := m["signature"]
if ok {
    s.Signature = []byte(sig.(string))
}

最佳答案

当您尝试解码其余字段时,您的代码进入无限循环的原因是,我推测,UnmarshalJSON 的实现在完成解码验证 key 后调用 json.Unmarshal 与接收方一起调用,后者又调用接收方的 UnmarshalJSON 方法,因此它们会无限期地相互调用。

你可以做的是使用现有类型作为其定义来创建一个临时类型,这将“保留结构”但“删除方法”,然后将其余字段解码为新类型的实例,并且,在解码完成后,将实例转换为原始类型并将其分配给接收者。

虽然这修复了无限循环,但它也重新引入了 json.Unmarshal 无法解码为非空接口(interface)类型的原始问题。要解决这个问题,您可以将新类型嵌入到另一个临时结构中,该结构具有与有问题的字段具有相同 json 标记的字段,这将导致它在 json.Unmarshal 工作时被“掩盖” .

type SingleKey struct {
    FQDN         string    `json:"fqdn"`
    Address      string    `json:"address"`
    Nonce        int64     `json:"nonce"`
    Challenge    []byte    `json:"challenge"`
    NetworkID    string    `json:"network_id"`
    Type         string    `json:"type"`
    VerifyingKey PublicKey `json:"verifying_key"`
    Signature    []byte    `json:"signature"`
}

func (s *SingleKey) UnmarshalJSON(data []byte) error {
    type _SingleKey SingleKey
    var temp struct {
        RawKey json.RawMessage `json:"verifying_key"`
        _SingleKey
    }
    if err := json.Unmarshal(data, &temp); err != nil {
        return err
    }
    *s = SingleKey(temp._SingleKey)

    switch s.Type {
    case "verifying_key":
        s.VerifyingKey = &PublicKeyImpl{}
    // other cases ...
    }

    return json.Unmarshal([]byte(temp.RawKey), s.VerifyingKey)
}

https://play.golang.org/p/L3gdQZF47uN

关于json - 执行自定义解码后解码剩余的 JSON,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62951510/

相关文章:

ios - Swift - 从 JSON 响应形成数组

go - 重新连接后如何避免双重连接关闭?

ssl - 简单的 GoLang SSL 示例

php - 使用 JavaScript 进行 RPC(远程过程调用)

javascript - 如何获取JSON文本的特定部分

go - 如何为 map 平铺器执行图像抽取?

postgresql - 如何从表 GORM 中获取工资列的总和

go - 让 TCP 服务器保持 GO 监听的最佳方法是什么?

sql - Json数组列拆分成行SQL

java - Java中Arraylist转Json的方法