我目前无法解组由 jsonpb 生成的JSON代码段。也许这只是我的一种误解,但是在查看测试时,我希望它会以某种方式起作用。
以下是pb.proto
的相关代码段:
syntax = "proto3";
package pb;
message Parameter {
string name = 1;
oneof value {
string str_value = 2;
int32 int_value = 3;
bool bool_value = 4;
float float_value = 5;
}
}
message ParameterSet {
bytes raw = 1;
repeated Parameter parameters = 2;
}
message ParameterSets {
map<string,ParameterSet> sets = 1;
}
使用此简单代码段测试封送/拆组失败:
package main
import (
"fmt"
"github.com/gogo/protobuf/jsonpb"
"strings"
)
func main() {
m := jsonpb.Marshaler{}
str, err := m.MarshalToString(&pb.ParameterSets{Sets: map[string]*pb.ParameterSet{
"parameter": {
Raw: []byte{0, 1, 2, 3, 4, 5, 6, 1, 2},
Parameters: []*pb.Parameter{
{Name: "itest", Value: &pb.Parameter_IntValue{42}},
{Name: "stest", Value: &pb.Parameter_StrValue{"Foobar"}},
{Name: "btest", Value: &pb.Parameter_BoolValue{true}},
{Name: "ftest", Value: &pb.Parameter_FloatValue{41.99}},
},
},
}},)
fmt.Println(str)
fmt.Println(err)
sets := pb.ParameterSets{}
err = jsonpb.Unmarshal(strings.NewReader(str), &sets)
fmt.Println(sets)
fmt.Println(err)
}
结果为:
{"sets":{"parameter":{"raw":"AAECAwQFBgEC","parameters":[{"name":"itest","intValue":42},{"name":"stest","strValue":"Foobar"},{"name":"btest","boolValue":true},{"name":"ftest","floatValue":41.99}]}}}
<nil>
{map[]}
unknown field "intValue" in pb.Parameter
如何将 oneof 值重新返回到原始对象中?
答案 0 :(得分:0)
由于两个供应商文件夹,您有一个Type混淆。在两个供应商文件夹中声明的类型不相同,即使它们的代码完全相同。
因此例如:
prototest-master/vendor/github.com/gogo/proto/messageSet
(A)与prototest-master/
proto /vendor/github.com/gogo/proto/messageSet
(B)的类型不同,即使它们的导入相同(github.com/gogo/proto
)
在项目的main.go
中,封送封送程序jsonpb.Marshaler{}
的构造使用(A)中的类型,而实际消息&pb.ParameterSets{...
这样的消息则使用(B)中的类型来构造自身。 / p>
由于jsonpb
似乎做了很多反射工作,因此在将两种类型混合使用时会中断。
一个更好的解决方案是仅使用一个vendor
文件夹来明确每个人使用的类型。我只会放弃(B)供应商文件夹,因为它没有添加任何内容。
答案 1 :(得分:0)
我认为手动构建消息并不安全,因为您无法保证结果JSON与jsonpb.Marshal
产生的结果完全匹配。最好只实例化Parameter
。
This github issue讨论了一种与您的情况类似的方案,one of the solutions可能会为您提供帮助:
package main
import (
"fmt"
"strings"
"github.com/golang/protobuf/jsonpb"
"github.com/golang/protobuf/proto"
)
func main() {
msg := &Person{
Name: "Allen",
Age: 30,
Married: true,
Number: &Person_F{float32(14500.6)},
}
m := jsonpb.Marshaler{}
js, err := m.MarshalToString(msg)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("json output ==> %v\n", js)
msg2 := &Person{}
if err := jsonpb.Unmarshal(strings.NewReader(js), msg2); err != nil {
fmt.Println(err)
return
}
fmt.Printf("%+v\n", proto.MarshalTextString(msg2))
}