Golang将通用JSON对象解码为多种格式之一 [英] Golang Decoding Generic JSON Objects to One of Many Formats

查看:408
本文介绍了Golang将通用JSON对象解码为多种格式之一的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究一种基于通用JSON的消息传递协议。我想要做的是有一个 BaseMessage ,它具有一般信息,如类型时间戳等,但同时我希望能够为特定类型的数据定义更具体的消息结构。



例如:

 类型消息struct {
类型字符串`json:type`
时间戳字符串`json:timestamp`



类型EventMessage结构{
消息
EventType字符串
EventCreator字符串
EventData接口{}
}

我有一组处理程序并确定哪个处理程序应该处理消息我将JSON解码为一般 Message 首先键入以检查 Type 字段。对于这个例子,我会得到与事件消息类型相关联的处理程序。

当我想要将 EventMessage 类型声明为结构时遇到问题。



以下代码非常粗糙,但希望它显示我对如何处理消息的一般想法。

 类型Handler func(msg Message)消息
handlers:= make(map [string] Handler)

var msg消息
decoder.Decode(& msg)
handler:= handlers [msg.Type]
handler(msg)

我试图使用 interface {} ,但是JSON解码器只是创建一个映射,然后我不能断言任何一种类型。我已经想出了可能的解决方法,但它非常难看,可能效率不高,并且很可能出现错误。我想保持简单直接的事情,这样可以很容易地维护这些代码。

是否有一种方法可以处理Golang中的通用JSON对象,以便解码JSON可以是许多结构格式之一吗?



我也玩过在数据接口{} 在主要的 Message struct中,但是我遇到了同样的问题,无法在接口上声明任何类型。必须有更好的方式来处理我只是缺少的JSON格式。

解决方案

处理这个问题的一种方法是定义用于 json.RawMessage 字段的消息的固定部分的结构来捕获变体部分的消息。将json.RawMessage解码为特定于该变体的类型:

  type消息struct {
类型字符串`json:类型`
时间戳字符串`json:timestamp`
数据json.RawMessage
}

类型事件结构{
类型字符串`json:type`
Creator字符串`json:creator`
}


var m消息
如果err:= json.Unmarshal(data,& m); err!= nil {
log.Fatal(err)
}
switch m.Type {
caseevent:
var e Event
if err:= json.Unmarshal([] byte(m.Data),& e); err!= nil {
log.Fatal(err)
}
fmt.Println(m.Type,e.Type,e.Creator)
默认值:
log.Fatal(bad message type)
}

游乐场示例


I am working on a general JSON based message passing protocol in golang. What I would like to do is have a BaseMessage that has general information like Type, timestamp, etc. But at the same time I want to be able to define more specific message structures for certain types of data.

For example:

type Message struct {
    Type      string `json:type`
    Timestamp string `json:timestamp`

}

type EventMessage struct {
    Message
    EventType string
    EventCreator string
    EventData interface{}
}

I have a set of handlers and to determine which handler should process the message I decode the JSON to the general Message type first to check the Type field. For this example I would get the handler associated with an "Event" message type.

I run into problems when I then want to assert the EventMessage type onto the structure.

The following code is very rough, but hopefully it displays my general idea of how I am trying to handle the messages.

type Handler func(msg Message) Message
handlers := make(map[string]Handler)

var msg Message
decoder.Decode(&msg)
handler := handlers[msg.Type]
handler(msg)

I have tried to use an interface{} but then the JSON decoder just creates a map which I then cant assert either type on. I have figured out workarounds that make it possible, but its very ugly, probably not efficient, and most likely error prone. I would like to keep things simple and straightforward so this code can be easily maintained.

Is there a method of handling generic JSON objects in Golang so that the decoded JSON could be one of many struct formats?

I have also played with the idea of having more specific info in a Data interface{} in the main Message struct, but then I run into the same problem of not being able to assert any types onto the interface. There has to be a better way to handle JSON formats that I am just missing.

解决方案

One way to handle this is to define a struct for the fixed part of the message with a json.RawMessage field to capture the variant part of the message. Decode the json.RawMessage to a type specific to the variant:

type Message struct {
  Type      string `json:type`
  Timestamp string `json:timestamp`
  Data      json.RawMessage
}  

type Event struct {
   Type    string `json:type`
   Creator string `json:creator`
}


var m Message
if err := json.Unmarshal(data, &m); err != nil {
    log.Fatal(err)
}
switch m.Type {
case "event":
    var e Event
    if err := json.Unmarshal([]byte(m.Data), &e); err != nil {
        log.Fatal(err)
    }
    fmt.Println(m.Type, e.Type, e.Creator)
default:
    log.Fatal("bad message type")
}

playground example

这篇关于Golang将通用JSON对象解码为多种格式之一的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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