英文:
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.Unmarshaler
将 json.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(*<json.RawMessage>*), 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 (
"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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论