执行自定义解组后解组剩余的JSON [英] Unmarshal remaining JSON after performing custom unmarshalling

查看:55
本文介绍了执行自定义解组后解组剩余的JSON的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个JSON对象,其中包含接口的实现.我正在尝试使用该JSON并将其编组为结构,同时创建接口的实现.

I have a JSON object That contains an implementation of an interface within it. I'm attempting to take that JSON and marshal it into a struct whilst creating the implementation of the interface.

我已经设法通过自定义JSON解组函数来实现该接口,但是我正在拼凑如何整理其余字段的方法

I've managed to get it to implement the interface with a custom JSON unmarshal function however I'm struggling to piece together how to then marshal the rest of the fields

我已经在Go游乐场创建了一个示例

I've created an example in the Go playground

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

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

My JSON being passed into my application is

{

   "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并为其余字段传递一个新的结构,但这似乎使我陷入无限循环,我的应用程序挂起然后崩溃

I've attempted to do a json.Unmarshal and pass in a new struct for the remaining fields however it seems to put me in an infinite loop, my application hangs and then crashes

到目前为止,我想出的最好的解决方案是将JSON编组到一个"map [string] interface {}"中,并分别处理每个字段,尽管这样感觉很笨拙

The best solution I've come up with so far is to marshal the JSON into a `map[string]interface{} and do each field separately, this feels very clunky though

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))
}

推荐答案

看看您在自定义解组功能中所做的事情,您似乎正在传入以字段名称为索引的地图,而 reflect.Type .对我而言,这表明密钥对于不同的有效负载可能有所不同,但是每个密钥都有与之关联的不同类型.您可以使用简单的包装器类型完美地处理这样的数据:

Looking at what you've done in your custom unmarshalling function, you seem to be passing in a map with the name of fields as index, and the reflect.Type you want to unmarshal said value into. That, to me, suggests that the keys might be different for different payloads, but that each key has a distinct type associated with it. You can perfectly handle data like this with a simple wrapper type:

type WrappedSingleKey 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 json.RawMessage `json:"verifying_key"`
    OtherKey     json.RawMessage `json:"other_key"`
    Signature    []byte          `json:"signature"`
}

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,omitempty"`
    OtherType    *OtherKey  `json:"other_key,omitempty"`
    Signature    []byte     `json:"signature"`
}

因此,我已将您的 VerifyingKey 字段的类型更改为 json.RawMessage .这基本上是在告诉 json.Unmarshal 将其保留为原始JSON输入.对于每个自定义/可选字段,添加一个相应的RawMessage字段.

So I've changed the type of your VerifyingKey field to a json.RawMessage. That's basically telling json.Unmarshal to leave that as raw JSON input. For every custom/optional field, add a corresponding RawMessage field.

在展开类型中,我已将 VerifyingKey 更改为指针,并在标签中添加了 omitempty 位.这仅仅是为了适应多种类型,而不必担心自定义编组来避免空字段,例如我包含的 OtherType 字段.要获得所需的东西,然后:

In the unwrapped type, I've changed VerifyingKey to a pointer and added the omitempty bit to the tag. That's just to accomodate mutliple types, and not have to worry about custom marshalling to avoid empty fields, like the included OtherType field I have. To get what you need, then:

func (s *SingleKey) UnmarshalJSON(data []byte) error {
    w := WrappedSingleKey{} // create wrapped instance
    if err := json.Unmarshal(data, &w); err != nil {
        return err
    }
    switch w.Type {
    case "verifying_key":
       var pk PublicKey
       if err := json.Unmarshal([]byte(w.VerifyingKey), &pk); err != nil {
           return err
       }
       s.VerifyingKey = &pk // assign
    case "other_key":
        var ok OtherKey
        if err := json.Unmarshal([]byte(w.OtherKey), &ok); err != nil {
            return err
        }
        s.OtherKey = &ok
    }
    // copy over the fields that didn't require anything special
    s.FQDN = w.FQDN
    s.Address = w.Address
}

这是一种相当简单的方法,它消除了反射,大量的功能,并且非常常用.这也很适合代码生成.但是,各个字段的单独分配有些繁琐.您可能会认为可以通过将 SingleKey 类型嵌入包装器中来解决此问题,但请注意:这将递归调用您的自定义unmarshaller函数.

This is a fairly simple approach, does away with the reflection, tons of functions, and is quite commonly used. It's something that lends itself quite well to code generation, too. The individual assignment of the fields is a bit tedious, though. You might think that you can solve that by embedding the SingleKey type into the wrapper, but be careful: this will recursively call your custom unmarshaller function.

例如,您可以将 WRapped 类型中的所有字段更新为指针,并使其指向您实际类型上的字段.不需要手动复制字段...,这完全取决于您.

You could, for example, update all the fields in the WRapped type to be pointers, and have them point to fields on your actual type. That does away with the manual copying of fields... It's up to you, really.

我没有测试这段代码,只是在编写过程中编写了它.这是我过去使用过的东西,我相信我在这里写的内容应该可以工作,但是不能保证(例如:您可能需要对其进行一些调试)

I didn't test this code, just wrote it as I went along. It's something I've used in the past, and I believe what I wrote here should work, but no guarantees (as in: you might need to debug it a bit)

这篇关于执行自定义解组后解组剩余的JSON的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆