encoding/jsonpb: fix unmarshaling of NullValue field

A JSON "null" field should set the NullValue enum field because
NullValue has the custom encoding format of "null".

Change-Id: I2bfa0900de64d7e2874f7c6db04b1cbc0b61b904
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/170107
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/encoding/jsonpb/decode.go b/encoding/jsonpb/decode.go
index 8511a8d..7655054 100644
--- a/encoding/jsonpb/decode.go
+++ b/encoding/jsonpb/decode.go
@@ -225,8 +225,8 @@
 		seenNums.Set(num)
 
 		// No need to set values for JSON null unless the field type is
-		// google.protobuf.Value.
-		if o.decoder.Peek() == json.Null && !isKnownValue(fd) {
+		// google.protobuf.Value or google.protobuf.NullValue.
+		if o.decoder.Peek() == json.Null && !isKnownValue(fd) && !isNullValue(fd) {
 			o.decoder.Read()
 			continue
 		}
@@ -277,6 +277,16 @@
 	return nil, protoregistry.NotFound
 }
 
+func isKnownValue(fd pref.FieldDescriptor) bool {
+	md := fd.MessageType()
+	return md != nil && md.FullName() == "google.protobuf.Value"
+}
+
+func isNullValue(fd pref.FieldDescriptor) bool {
+	ed := fd.EnumType()
+	return ed != nil && ed.FullName() == "google.protobuf.NullValue"
+}
+
 // unmarshalSingular unmarshals to the non-repeated field specified by the given
 // FieldDescriptor.
 func (o UnmarshalOptions) unmarshalSingular(knownFields pref.KnownFields, fd pref.FieldDescriptor) error {
@@ -509,6 +519,12 @@
 			return pref.Value{}, err
 		}
 		return pref.ValueOf(pref.EnumNumber(n)), nil
+
+	case json.Null:
+		// This is only valid for google.protobuf.NullValue.
+		if isNullValue(fd) {
+			return pref.ValueOf(pref.EnumNumber(0)), nil
+		}
 	}
 
 	return pref.Value{}, unexpectedJSONError{jval}
diff --git a/encoding/jsonpb/decode_test.go b/encoding/jsonpb/decode_test.go
index 1e9bd98..e7f4239 100644
--- a/encoding/jsonpb/decode_test.go
+++ b/encoding/jsonpb/decode_test.go
@@ -439,24 +439,31 @@
 		desc:         "enum set to number string",
 		inputMessage: &pb3.Enums{},
 		inputText: `{
-  "sEnum": "1",
+  "sEnum": "1"
 }`,
 		wantErr: true,
 	}, {
 		desc:         "enum set to invalid named",
 		inputMessage: &pb3.Enums{},
 		inputText: `{
-  "sEnum": "UNNAMED",
+  "sEnum": "UNNAMED"
 }`,
 		wantErr: true,
 	}, {
 		desc:         "enum set to not enum",
 		inputMessage: &pb3.Enums{},
 		inputText: `{
-  "sEnum": true,
+  "sEnum": true
 }`,
 		wantErr: true,
 	}, {
+		desc:         "enum set to JSON null",
+		inputMessage: &pb3.Enums{},
+		inputText: `{
+  "sEnum": null
+}`,
+		wantMessage: &pb3.Enums{},
+	}, {
 		desc:         "proto name",
 		inputMessage: &pb3.JSONNames{},
 		inputText: `{
@@ -1478,6 +1485,20 @@
 		},
 		wantErr: true,
 	}, {
+		desc:         "NullValue field with JSON null",
+		inputMessage: &pb2.KnownTypes{},
+		inputText: `{
+  "optNull": null
+}`,
+		wantMessage: &pb2.KnownTypes{OptNull: new(knownpb.NullValue)},
+	}, {
+		desc:         "NullValue field with string",
+		inputMessage: &pb2.KnownTypes{},
+		inputText: `{
+  "optNull": "NULL_VALUE"
+}`,
+		wantMessage: &pb2.KnownTypes{OptNull: new(knownpb.NullValue)},
+	}, {
 		desc:         "BytesValue",
 		inputMessage: &knownpb.BytesValue{},
 		inputText:    `"aGVsbG8="`,
diff --git a/encoding/jsonpb/encode_test.go b/encoding/jsonpb/encode_test.go
index 005de06..96e21f2 100644
--- a/encoding/jsonpb/encode_test.go
+++ b/encoding/jsonpb/encode_test.go
@@ -1177,6 +1177,12 @@
 		input: &knownpb.Empty{},
 		want:  `{}`,
 	}, {
+		desc:  "NullValue field",
+		input: &pb2.KnownTypes{OptNull: new(knownpb.NullValue)},
+		want: `{
+  "optNull": null
+}`,
+	}, {
 		desc:    "Value empty",
 		input:   &knownpb.Value{},
 		wantErr: true,
diff --git a/encoding/jsonpb/well_known_types.go b/encoding/jsonpb/well_known_types.go
index db1e365..788e314 100644
--- a/encoding/jsonpb/well_known_types.go
+++ b/encoding/jsonpb/well_known_types.go
@@ -547,11 +547,6 @@
 	return errors.New("%s: none of the variants is set", msgType.FullName())
 }
 
-func isKnownValue(fd pref.FieldDescriptor) bool {
-	md := fd.MessageType()
-	return md != nil && md.FullName() == "google.protobuf.Value"
-}
-
 func (o UnmarshalOptions) unmarshalKnownValue(m pref.Message) error {
 	var nerr errors.NonFatal
 	knownFields := m.KnownFields()