encoding/jsonpb: add support for unmarshaling Any

Also added json.Decoder.Clone API for unmarshaling Any to look
ahead remaining bytes for @type field.

Change-Id: I2f803743534dfb64f9092d716805b115faa5975a
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/170102
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/encoding/jsonpb/decode_test.go b/encoding/jsonpb/decode_test.go
index a1ad766..1e9bd98 100644
--- a/encoding/jsonpb/decode_test.go
+++ b/encoding/jsonpb/decode_test.go
@@ -1866,6 +1866,535 @@
 				},
 			},
 		},
+	}, {
+		desc:         "Any empty",
+		inputMessage: &knownpb.Any{},
+		inputText:    `{}`,
+		wantMessage:  &knownpb.Any{},
+	}, {
+		desc: "Any with non-custom message",
+		umo: jsonpb.UnmarshalOptions{
+			Resolver: preg.NewTypes((&pb2.Nested{}).ProtoReflect().Type()),
+		},
+		inputMessage: &knownpb.Any{},
+		inputText: `{
+  "@type": "foo/pb2.Nested",
+  "optString": "embedded inside Any",
+  "optNested": {
+    "optString": "inception"
+  }
+}`,
+		wantMessage: func() proto.Message {
+			m := &pb2.Nested{
+				OptString: scalar.String("embedded inside Any"),
+				OptNested: &pb2.Nested{
+					OptString: scalar.String("inception"),
+				},
+			}
+			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: "foo/pb2.Nested",
+				Value:   b,
+			}
+		}(),
+	}, {
+		desc: "Any with empty embedded message",
+		umo: jsonpb.UnmarshalOptions{
+			Resolver: preg.NewTypes((&pb2.Nested{}).ProtoReflect().Type()),
+		},
+		inputMessage: &knownpb.Any{},
+		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,
+	}, {
+		desc: "Any with missing required error",
+		umo: jsonpb.UnmarshalOptions{
+			Resolver: preg.NewTypes((&pb2.PartialRequired{}).ProtoReflect().Type()),
+		},
+		inputMessage: &knownpb.Any{},
+		inputText: `{
+  "@type": "pb2.PartialRequired",
+  "optString": "embedded inside Any"
+}`,
+		wantMessage: func() proto.Message {
+			m := &pb2.PartialRequired{
+				OptString: scalar.String("embedded inside Any"),
+			}
+			b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
+			// TODO: Marshal may fail due to required field not set at some
+			// point. Need to ignore required not set error here.
+			if err != nil {
+				t.Fatalf("error in binary marshaling message for Any.value: %v", err)
+			}
+			return &knownpb.Any{
+				TypeUrl: string(m.ProtoReflect().Type().FullName()),
+				Value:   b,
+			}
+		}(),
+		wantErr: true,
+	}, {
+		desc: "Any with partial required and AllowPartial",
+		umo: jsonpb.UnmarshalOptions{
+			AllowPartial: true,
+			Resolver:     preg.NewTypes((&pb2.PartialRequired{}).ProtoReflect().Type()),
+		},
+		inputMessage: &knownpb.Any{},
+		inputText: `{
+  "@type": "pb2.PartialRequired",
+  "optString": "embedded inside Any"
+}`,
+		wantMessage: func() proto.Message {
+			m := &pb2.PartialRequired{
+				OptString: scalar.String("embedded inside Any"),
+			}
+			b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
+			// TODO: Marshal may fail due to required field not set at some
+			// point. Need to ignore required not set error here.
+			if err != nil {
+				t.Fatalf("error in binary marshaling message for Any.value: %v", err)
+			}
+			return &knownpb.Any{
+				TypeUrl: string(m.ProtoReflect().Type().FullName()),
+				Value:   b,
+			}
+		}(),
+	}, {
+		desc: "Any with invalid UTF8",
+		umo: jsonpb.UnmarshalOptions{
+			Resolver: preg.NewTypes((&pb2.Nested{}).ProtoReflect().Type()),
+		},
+		inputMessage: &knownpb.Any{},
+		inputText: `{
+  "optString": "` + "abc\xff" + `",
+  "@type": "foo/pb2.Nested"
+}`,
+		wantMessage: func() proto.Message {
+			m := &pb2.Nested{
+				OptString: scalar.String("abc\xff"),
+			}
+			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: "foo/pb2.Nested",
+				Value:   b,
+			}
+		}(),
+		wantErr: true,
+	}, {
+		desc: "Any with BoolValue",
+		umo: jsonpb.UnmarshalOptions{
+			Resolver: preg.NewTypes((&knownpb.BoolValue{}).ProtoReflect().Type()),
+		},
+		inputMessage: &knownpb.Any{},
+		inputText: `{
+  "@type": "type.googleapis.com/google.protobuf.BoolValue",
+  "value": true
+}`,
+		wantMessage: func() proto.Message {
+			m := &knownpb.BoolValue{Value: true}
+			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.BoolValue",
+				Value:   b,
+			}
+		}(),
+	}, {
+		desc: "Any with Empty",
+		umo: jsonpb.UnmarshalOptions{
+			Resolver: preg.NewTypes((&knownpb.Empty{}).ProtoReflect().Type()),
+		},
+		inputMessage: &knownpb.Any{},
+		inputText: `{
+  "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,
+			}
+		}(),
+	}, {
+		desc: "Any with missing Empty",
+		umo: jsonpb.UnmarshalOptions{
+			Resolver: preg.NewTypes((&knownpb.Empty{}).ProtoReflect().Type()),
+		},
+		inputMessage: &knownpb.Any{},
+		inputText: `{
+  "@type": "type.googleapis.com/google.protobuf.Empty"
+}`,
+		wantErr: true,
+	}, {
+		desc: "Any with StringValue containing invalid UTF8",
+		umo: jsonpb.UnmarshalOptions{
+			Resolver: preg.NewTypes((&knownpb.StringValue{}).ProtoReflect().Type()),
+		},
+		inputMessage: &knownpb.Any{},
+		inputText: `{
+  "@type": "google.protobuf.StringValue",
+  "value": "` + "abc\xff" + `"
+}`,
+		wantMessage: func() proto.Message {
+			m := &knownpb.StringValue{Value: "abc\xff"}
+			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: "google.protobuf.StringValue",
+				Value:   b,
+			}
+		}(),
+		wantErr: true,
+	}, {
+		desc: "Any with Int64Value",
+		umo: jsonpb.UnmarshalOptions{
+			Resolver: preg.NewTypes((&knownpb.Int64Value{}).ProtoReflect().Type()),
+		},
+		inputMessage: &knownpb.Any{},
+		inputText: `{
+  "@type": "google.protobuf.Int64Value",
+  "value": "42"
+}`,
+		wantMessage: func() proto.Message {
+			m := &knownpb.Int64Value{Value: 42}
+			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: "google.protobuf.Int64Value",
+				Value:   b,
+			}
+		}(),
+	}, {
+		desc: "Any with invalid Int64Value",
+		umo: jsonpb.UnmarshalOptions{
+			Resolver: preg.NewTypes((&knownpb.Int64Value{}).ProtoReflect().Type()),
+		},
+		inputMessage: &knownpb.Any{},
+		inputText: `{
+  "@type": "google.protobuf.Int64Value",
+  "value": "forty-two"
+}`,
+		wantErr: true,
+	}, {
+		desc: "Any with invalid UInt64Value",
+		umo: jsonpb.UnmarshalOptions{
+			Resolver: preg.NewTypes((&knownpb.UInt64Value{}).ProtoReflect().Type()),
+		},
+		inputMessage: &knownpb.Any{},
+		inputText: `{
+  "@type": "google.protobuf.UInt64Value",
+  "value": -42
+}`,
+		wantErr: true,
+	}, {
+		desc: "Any with Duration",
+		umo: jsonpb.UnmarshalOptions{
+			Resolver: preg.NewTypes((&knownpb.Duration{}).ProtoReflect().Type()),
+		},
+		inputMessage: &knownpb.Any{},
+		inputText: `{
+  "@type": "type.googleapis.com/google.protobuf.Duration",
+  "value": "0s"
+}`,
+		wantMessage: func() proto.Message {
+			m := &knownpb.Duration{}
+			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.Duration",
+				Value:   b,
+			}
+		}(),
+	}, {
+		desc: "Any with Value of StringValue",
+		umo: jsonpb.UnmarshalOptions{
+			Resolver: preg.NewTypes((&knownpb.Value{}).ProtoReflect().Type()),
+		},
+		inputMessage: &knownpb.Any{},
+		inputText: `{
+  "@type": "google.protobuf.Value",
+  "value": "` + "abc\xff" + `"
+}`,
+		wantMessage: func() proto.Message {
+			m := &knownpb.Value{Kind: &knownpb.Value_StringValue{"abc\xff"}}
+			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: "google.protobuf.Value",
+				Value:   b,
+			}
+		}(),
+		wantErr: true,
+	}, {
+		desc: "Any with Value of NullValue",
+		umo: jsonpb.UnmarshalOptions{
+			Resolver: preg.NewTypes((&knownpb.Value{}).ProtoReflect().Type()),
+		},
+		inputMessage: &knownpb.Any{},
+		inputText: `{
+  "@type": "google.protobuf.Value",
+  "value": null
+}`,
+		wantMessage: func() proto.Message {
+			m := &knownpb.Value{Kind: &knownpb.Value_NullValue{}}
+			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: "google.protobuf.Value",
+				Value:   b,
+			}
+		}(),
+	}, {
+		desc: "Any with Struct",
+		umo: jsonpb.UnmarshalOptions{
+			Resolver: preg.NewTypes(
+				(&knownpb.Struct{}).ProtoReflect().Type(),
+				(&knownpb.Value{}).ProtoReflect().Type(),
+				(&knownpb.BoolValue{}).ProtoReflect().Type(),
+				knownpb.NullValue_NULL_VALUE.Type(),
+				(&knownpb.StringValue{}).ProtoReflect().Type(),
+			),
+		},
+		inputMessage: &knownpb.Any{},
+		inputText: `{
+  "@type": "google.protobuf.Struct",
+  "value": {
+    "bool": true,
+    "null": null,
+    "string": "hello",
+    "struct": {
+      "string": "world"
+    }
+  }
+}`,
+		wantMessage: func() proto.Message {
+			m := &knownpb.Struct{
+				Fields: map[string]*knownpb.Value{
+					"bool":   {Kind: &knownpb.Value_BoolValue{true}},
+					"null":   {Kind: &knownpb.Value_NullValue{}},
+					"string": {Kind: &knownpb.Value_StringValue{"hello"}},
+					"struct": {
+						Kind: &knownpb.Value_StructValue{
+							&knownpb.Struct{
+								Fields: map[string]*knownpb.Value{
+									"string": {Kind: &knownpb.Value_StringValue{"world"}},
+								},
+							},
+						},
+					},
+				},
+			}
+			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: "google.protobuf.Struct",
+				Value:   b,
+			}
+		}(),
+	}, {
+		desc:         "Any with missing @type",
+		umo:          jsonpb.UnmarshalOptions{},
+		inputMessage: &knownpb.Any{},
+		inputText: `{
+  "value": {}
+}`,
+		wantErr: true,
+	}, {
+		desc:         "Any with empty @type",
+		inputMessage: &knownpb.Any{},
+		inputText: `{
+  "@type": ""
+}`,
+		wantErr: true,
+	}, {
+		desc: "Any with duplicate @type",
+		umo: jsonpb.UnmarshalOptions{
+			Resolver: preg.NewTypes(
+				(&pb2.Nested{}).ProtoReflect().Type(),
+				(&knownpb.StringValue{}).ProtoReflect().Type(),
+			),
+		},
+		inputMessage: &knownpb.Any{},
+		inputText: `{
+  "@type": "google.protobuf.StringValue",
+  "value": "hello",
+  "@type": "pb2.Nested"
+}`,
+		wantErr: true,
+	}, {
+		desc: "Any with duplicate value",
+		umo: jsonpb.UnmarshalOptions{
+			Resolver: preg.NewTypes((&knownpb.StringValue{}).ProtoReflect().Type()),
+		},
+		inputMessage: &knownpb.Any{},
+		inputText: `{
+  "@type": "google.protobuf.StringValue",
+  "value": "hello",
+  "value": "world"
+}`,
+		wantErr: true,
+	}, {
+		desc: "Any with unknown field",
+		umo: jsonpb.UnmarshalOptions{
+			Resolver: preg.NewTypes((&pb2.Nested{}).ProtoReflect().Type()),
+		},
+		inputMessage: &knownpb.Any{},
+		inputText: `{
+  "@type": "pb2.Nested",
+  "optString": "hello",
+  "unknown": "world"
+}`,
+		wantErr: true,
+	}, {
+		desc: "Any with embedded type containing Any",
+		umo: jsonpb.UnmarshalOptions{
+			Resolver: preg.NewTypes(
+				(&pb2.KnownTypes{}).ProtoReflect().Type(),
+				(&knownpb.Any{}).ProtoReflect().Type(),
+				(&knownpb.StringValue{}).ProtoReflect().Type(),
+			),
+		},
+		inputMessage: &knownpb.Any{},
+		inputText: `{
+  "@type": "pb2.KnownTypes",
+  "optAny": {
+    "@type": "google.protobuf.StringValue",
+	"value": "` + "abc\xff" + `"
+  }
+}`,
+		wantMessage: func() proto.Message {
+			m1 := &knownpb.StringValue{Value: "abc\xff"}
+			b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m1)
+			if err != nil {
+				t.Fatalf("error in binary marshaling message for Any.value: %v", err)
+			}
+			m2 := &knownpb.Any{
+				TypeUrl: "google.protobuf.StringValue",
+				Value:   b,
+			}
+			m3 := &pb2.KnownTypes{OptAny: m2}
+			b, err = proto.MarshalOptions{Deterministic: true}.Marshal(m3)
+			if err != nil {
+				t.Fatalf("error in binary marshaling message for Any.value: %v", err)
+			}
+			return &knownpb.Any{
+				TypeUrl: "pb2.KnownTypes",
+				Value:   b,
+			}
+		}(),
+		wantErr: true,
+	}, {
+		desc: "well known types as field values",
+		umo: jsonpb.UnmarshalOptions{
+			Resolver: preg.NewTypes((&knownpb.Empty{}).ProtoReflect().Type()),
+		},
+		inputMessage: &pb2.KnownTypes{},
+		inputText: `{
+  "optBool": false,
+  "optInt32": 42,
+  "optInt64": "42",
+  "optUint32": 42,
+  "optUint64": "42",
+  "optFloat": 1.23,
+  "optDouble": 3.1415,
+  "optString": "hello",
+  "optBytes": "aGVsbG8=",
+  "optDuration": "123s",
+  "optTimestamp": "2019-03-19T23:03:21Z",
+  "optStruct": {
+    "string": "hello"
+  },
+  "optList": [
+    null,
+    "",
+    {},
+    []
+  ],
+  "optValue": "world",
+  "optEmpty": {},
+  "optAny": {
+    "@type": "google.protobuf.Empty",
+    "value": {}
+  },
+  "optFieldmask": "fooBar,barFoo"
+}`,
+		wantMessage: &pb2.KnownTypes{
+			OptBool:      &knownpb.BoolValue{Value: false},
+			OptInt32:     &knownpb.Int32Value{Value: 42},
+			OptInt64:     &knownpb.Int64Value{Value: 42},
+			OptUint32:    &knownpb.UInt32Value{Value: 42},
+			OptUint64:    &knownpb.UInt64Value{Value: 42},
+			OptFloat:     &knownpb.FloatValue{Value: 1.23},
+			OptDouble:    &knownpb.DoubleValue{Value: 3.1415},
+			OptString:    &knownpb.StringValue{Value: "hello"},
+			OptBytes:     &knownpb.BytesValue{Value: []byte("hello")},
+			OptDuration:  &knownpb.Duration{Seconds: 123},
+			OptTimestamp: &knownpb.Timestamp{Seconds: 1553036601},
+			OptStruct: &knownpb.Struct{
+				Fields: map[string]*knownpb.Value{
+					"string": {Kind: &knownpb.Value_StringValue{"hello"}},
+				},
+			},
+			OptList: &knownpb.ListValue{
+				Values: []*knownpb.Value{
+					{Kind: &knownpb.Value_NullValue{}},
+					{Kind: &knownpb.Value_StringValue{}},
+					{
+						Kind: &knownpb.Value_StructValue{
+							&knownpb.Struct{Fields: map[string]*knownpb.Value{}},
+						},
+					},
+					{
+						Kind: &knownpb.Value_ListValue{
+							&knownpb.ListValue{Values: []*knownpb.Value{}},
+						},
+					},
+				},
+			},
+			OptValue: &knownpb.Value{
+				Kind: &knownpb.Value_StringValue{"world"},
+			},
+			OptEmpty: &knownpb.Empty{},
+			OptAny: &knownpb.Any{
+				TypeUrl: "google.protobuf.Empty",
+			},
+			OptFieldmask: &knownpb.FieldMask{
+				Paths: []string{"foo_bar", "bar_foo"},
+			},
+		},
 	}}
 
 	for _, tt := range tests {