encoding/jsonpb: add unmarshal option to ignore unknown fields
This feature seems to be used quite a bit, and the conformance tests
treat this as required, perhaps as a "required option" since the
developer guide states:
"Proto3 JSON parser should reject unknown fields by default but may
provide an option to ignore unknown fields in parsing."
Also, all invalid UTF-8 errors in skipped values are also returned as it
is similar to a parse error, except it is a non-fatal one.
Change-Id: Ia26e9a355daecdbf99af23f3061353fffa32d47d
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/174017
Reviewed-by: Damien Neil <dneil@google.com>
diff --git a/encoding/jsonpb/decode_test.go b/encoding/jsonpb/decode_test.go
index 6226b07..8f92209 100644
--- a/encoding/jsonpb/decode_test.go
+++ b/encoding/jsonpb/decode_test.go
@@ -2008,18 +2008,14 @@
Resolver: preg.NewTypes((&pb2.Nested{}).ProtoReflect().Type()),
},
inputMessage: &knownpb.Any{},
- inputText: `{
- "@type": "foo/pb2.Nested"
-}`,
- wantMessage: &knownpb.Any{TypeUrl: "foo/pb2.Nested"},
+ inputText: `{"@type": "foo/pb2.Nested"}`,
+ wantMessage: &knownpb.Any{TypeUrl: "foo/pb2.Nested"},
}, {
desc: "Any without registered type",
umo: jsonpb.UnmarshalOptions{Resolver: preg.NewTypes()},
inputMessage: &knownpb.Any{},
- inputText: `{
- "@type": "foo/pb2.Nested"
-}`,
- wantErr: true,
+ inputText: `{"@type": "foo/pb2.Nested"}`,
+ wantErr: true,
}, {
desc: "Any with missing required error",
umo: jsonpb.UnmarshalOptions{
@@ -2129,17 +2125,9 @@
"value": {},
"@type": "type.googleapis.com/google.protobuf.Empty"
}`,
- wantMessage: func() proto.Message {
- m := &knownpb.Empty{}
- b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
- if err != nil {
- t.Fatalf("error in binary marshaling message for Any.value: %v", err)
- }
- return &knownpb.Any{
- TypeUrl: "type.googleapis.com/google.protobuf.Empty",
- Value: b,
- }
- }(),
+ wantMessage: &knownpb.Any{
+ TypeUrl: "type.googleapis.com/google.protobuf.Empty",
+ },
}, {
desc: "Any with missing Empty",
umo: jsonpb.UnmarshalOptions{
@@ -2499,6 +2487,109 @@
Paths: []string{"foo_bar", "bar_foo"},
},
},
+ }, {
+ desc: "DiscardUnknown: regular messages",
+ umo: jsonpb.UnmarshalOptions{DiscardUnknown: true},
+ inputMessage: &pb3.Nests{},
+ inputText: `{
+ "sNested": {
+ "unknown": {
+ "foo": 1,
+ "bar": [1, 2, 3]
+ }
+ },
+ "unknown": "not known"
+}`,
+ wantMessage: &pb3.Nests{SNested: &pb3.Nested{}},
+ }, {
+ desc: "DiscardUnknown: repeated",
+ umo: jsonpb.UnmarshalOptions{DiscardUnknown: true},
+ inputMessage: &pb2.Nests{},
+ inputText: `{
+ "rptNested": [
+ {"unknown": "blah"},
+ {"optString": "hello"}
+ ]
+}`,
+ wantMessage: &pb2.Nests{
+ RptNested: []*pb2.Nested{
+ {},
+ {OptString: scalar.String("hello")},
+ },
+ },
+ }, {
+ desc: "DiscardUnknown: map",
+ umo: jsonpb.UnmarshalOptions{DiscardUnknown: true},
+ inputMessage: &pb3.Maps{},
+ inputText: `{
+ "strToNested": {
+ "nested_one": {
+ "unknown": "what you see is not"
+ }
+ }
+}`,
+ wantMessage: &pb3.Maps{
+ StrToNested: map[string]*pb3.Nested{
+ "nested_one": {},
+ },
+ },
+ }, {
+ desc: "DiscardUnknown: extension",
+ umo: jsonpb.UnmarshalOptions{DiscardUnknown: true},
+ inputMessage: &pb2.Extensions{},
+ inputText: `{
+ "[pb2.opt_ext_nested]": {
+ "unknown": []
+ }
+}`,
+ wantMessage: func() proto.Message {
+ m := &pb2.Extensions{}
+ setExtension(m, pb2.E_OptExtNested, &pb2.Nested{})
+ return m
+ }(),
+ }, {
+ desc: "DiscardUnknown: Empty",
+ umo: jsonpb.UnmarshalOptions{DiscardUnknown: true},
+ inputMessage: &knownpb.Empty{},
+ inputText: `{"unknown": "something"}`,
+ wantMessage: &knownpb.Empty{},
+ }, {
+ desc: "DiscardUnknown: Any without type",
+ umo: jsonpb.UnmarshalOptions{DiscardUnknown: true},
+ inputMessage: &knownpb.Any{},
+ inputText: `{
+ "value": {"foo": "bar"},
+ "unknown": true
+}`,
+ wantMessage: &knownpb.Any{},
+ }, {
+ desc: "DiscardUnknown: Any",
+ umo: jsonpb.UnmarshalOptions{
+ DiscardUnknown: true,
+ Resolver: preg.NewTypes((&pb2.Nested{}).ProtoReflect().Type()),
+ },
+ inputMessage: &knownpb.Any{},
+ inputText: `{
+ "@type": "foo/pb2.Nested",
+ "unknown": "none"
+}`,
+ wantMessage: &knownpb.Any{
+ TypeUrl: "foo/pb2.Nested",
+ },
+ }, {
+ desc: "DiscardUnknown: Any with Empty",
+ umo: jsonpb.UnmarshalOptions{
+ DiscardUnknown: true,
+ Resolver: preg.NewTypes((&knownpb.Empty{}).ProtoReflect().Type()),
+ },
+ inputMessage: &knownpb.Any{},
+ inputText: `{
+ "@type": "type.googleapis.com/google.protobuf.Empty",
+ "value": {"unknown": 47}
+}`,
+ wantMessage: &knownpb.Any{
+ TypeUrl: "type.googleapis.com/google.protobuf.Empty",
+ },
}}
for _, tt := range tests {