golang: “json: 无法将数组解组为类型为字符串的 Go 值”

huangapple go评论91阅读模式
英文:

golang: "json: cannot unmarshal array into Go value of type string"

问题

我有一个 protobuf 消息:

message Event {
   string type = 1;
   string names = 2;
}

在底层数据源中,'names' 的类型最近从 string 改变为 []string,其中旧数据仍然是字符串,但新数据将是 []string。因此,当数据返回时,一些记录可能是字符串,而其他记录可能是 []string。为了保持响应格式的一致性,以防止客户端出错,我需要自定义解组(使用 jsonpb.Unmarshalerjson.Rawmessage 解组为 Event 类型),如果 'names' 是 []string,则将其转换为字符串(通过连接数组/切片中的值)。

在解组时,我遇到了以下错误:

json: 无法将数组解组为类型为 string 的 Go 值

请问有人可以提供关于如何解决这个问题的建议吗?

我尝试过使用 google.protobuf.Any,如下所示,但无法完全弄清楚解组部分:

message Event {
   string type = 1;
   google.protobuf.Any names = 2;
}

解组代码片段:

evnt := new(pb.Event)
unmarshaler := jsonpb.Unmarshaler{AllowUnknownFields: true}
unmarshaler.Unmarshal(bytes.NewReader(*<json.RawMessage>*), evnt)
英文:

I have a protobuf message

message Event {
   string type = 1;
   string names = 2;
}

The type for ‘names’ has recently changed from string to []string in the underlying data source where older data is still a string but new data is going to be []string.
So, when the data is returned, some records can have string and the rest can have []string.
I need to customize the unmarshaling (jsonpb.Unmarshaler is being used to unmarshal json.Rawmessage to Event type) and convert the ‘names’ to a string if it’s an []string (by concatenating the values from array/slice) in order to keep the response format consistent so client doesn't break.

I get this error while unmarshaling:

> json: cannot unmarshal array into Go value of type string

Can anyone please suggest on how this can be done?

I tried google.protobuf.Any like below but couldn’t completely figure the unmarshaling part.

message Event {
   string type = 1;
   google.protobuf.Any names = 2;
}

Unmarshall snippet:

evnt := new(pb.Event)
unmarshaler    = jsonpb.Unmarshaler{AllowUnknownFields: true}
unmarshaler.Unmarshal(bytes.NewReader(*&lt;json.RawMessage&gt;*), evnt)

答案1

得分: 1

将名称转换为类型,然后给它一个自定义的UnmarshalJSON方法。示例:

package main

import (
	"encoding/json"
	"fmt"
	"os"
	"strings"
)

type name struct {
	New []string
	Old string
}

type event struct {
	Type string `json:"type"`
	Name name   `json:"name"`
}

func do(j string) {
	var e event
	err := json.Unmarshal([]byte(j), &e)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to unmarshall %s: %s\n", j, err)
		return
	}
	fmt.Printf("%v\n", e)
}

func (n *name) UnmarshalJSON(text []byte) error {
	t := strings.TrimSpace(string(text))
	if strings.HasPrefix(t, "[") {
		return json.Unmarshal(text, &n.New)
	}
	return json.Unmarshal(text, &n.Old)
}

func main() {
	jsonstring := `{"type":"a","name":"rodney"}`
	jsonarray := `{"type":"a","name":["rodney","dangerfield"]}`
	do(jsonstring)
	do(jsonarray)
}

Playground: https://go.dev/play/p/sNtUZKHC_Rt

英文:

Make the name into a type then give it a custom UnmarshalJSON method. Example:

package main

import (
	&quot;encoding/json&quot;
	&quot;fmt&quot;
	&quot;os&quot;
	&quot;strings&quot;
)

type name struct {
	New []string
	Old string
}

type event struct {
	Type string `json:&quot;type&quot;`
	Name name   `json:&quot;name&quot;`
}

func do(j string) {
	var e event
	err := json.Unmarshal([]byte(j), &amp;e)
	if err != nil {
		fmt.Fprintf(os.Stderr, &quot;Failed to unmarshall %s: %s\n&quot;, j, err)
		return
	}
	fmt.Printf(&quot;%v\n&quot;, e)
}

func (n *name) UnmarshalJSON(text []byte) error {
	t := strings.TrimSpace(string(text))
	if strings.HasPrefix(t, &quot;[&quot;) {
		return json.Unmarshal(text, &amp;n.New)
	}
	return json.Unmarshal(text, &amp;n.Old)
}

func main() {
	jsonstring := `{&quot;type&quot;:&quot;a&quot;,&quot;name&quot;:&quot;rodney&quot;}`
	jsonarray := `{&quot;type&quot;:&quot;a&quot;,&quot;name&quot;:[&quot;rodney&quot;,&quot;dangerfield&quot;]}`
	do(jsonstring)
	do(jsonarray)
}

Playground: https://go.dev/play/p/sNtUZKHC_Rt

huangapple
  • 本文由 发表于 2022年6月30日 03:23:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/72806808.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定