Kaynağa Gözat

jsonpb: Don't emit zero value proto3 fields by default.

This aligns the default behaviour with the spec
(https://developers.google.com/protocol-buffers/docs/proto3#json),
but also adds a Marshaler option to control it.

Fixes #122.
David Symonds 10 yıl önce
ebeveyn
işleme
45bba206dd
2 değiştirilmiş dosya ile 31 ekleme ve 4 silme
  1. 29 3
      jsonpb/jsonpb.go
  2. 2 1
      jsonpb/jsonpb_test.go

+ 29 - 3
jsonpb/jsonpb.go

@@ -56,11 +56,14 @@ var (
 )
 
 // Marshaler is a configurable object for converting between
-// protocol buffer objects and a JSON representation for them
+// protocol buffer objects and a JSON representation for them.
 type Marshaler struct {
 	// Whether to render enum values as integers, as opposed to string values.
 	EnumsAsInts bool
 
+	// Whether to render fields with zero values.
+	EmitDefaults bool
+
 	// A string to indent each level by. The presence of this field will
 	// also cause a space to appear between the field separator and
 	// value, and for newlines to be appear between fields and array
@@ -106,8 +109,6 @@ func (m *Marshaler) marshalObject(out *errWriter, v proto.Message, indent string
 			continue
 		}
 
-		// TODO: proto3 objects should have default values omitted.
-
 		// IsNil will panic on most value kinds.
 		switch value.Kind() {
 		case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
@@ -116,6 +117,31 @@ func (m *Marshaler) marshalObject(out *errWriter, v proto.Message, indent string
 			}
 		}
 
+		if !m.EmitDefaults {
+			switch value.Kind() {
+			case reflect.Bool:
+				if !value.Bool() {
+					continue
+				}
+			case reflect.Int32, reflect.Int64:
+				if value.Int() == 0 {
+					continue
+				}
+			case reflect.Uint32, reflect.Uint64:
+				if value.Uint() == 0 {
+					continue
+				}
+			case reflect.Float32, reflect.Float64:
+				if value.Float() == 0 {
+					continue
+				}
+			case reflect.String:
+				if value.Len() == 0 {
+					continue
+				}
+			}
+		}
+
 		// Oneof fields need special handling.
 		if valueField.Tag.Get("protobuf_oneof") != "" {
 			// value is an interface containing &T{real_value}.

+ 2 - 1
jsonpb/jsonpb_test.go

@@ -291,7 +291,8 @@ var marshalingTests = []struct {
 		&pb.Widget{Color: pb.Widget_BLUE.Enum()}, colorPrettyJSON},
 	{"unknown enum value object", marshalerAllOptions,
 		&pb.Widget{Color: pb.Widget_Color(1000).Enum(), RColor: []pb.Widget_Color{pb.Widget_RED}}, colorListPrettyJSON},
-	{"proto3 object with empty value", marshaler, &pb.Simple3{}, `{"dub":0}`},
+	{"empty value", marshaler, &pb.Simple3{}, `{}`},
+	{"empty value emitted", Marshaler{EmitDefaults: true}, &pb.Simple3{}, `{"dub":0}`},
 	{"map<int64, int32>", marshaler, &pb.Mappy{Nummy: map[int64]int32{1: 2, 3: 4}}, `{"nummy":{"1":2,"3":4}}`},
 	{"map<int64, int32>", marshalerAllOptions, &pb.Mappy{Nummy: map[int64]int32{1: 2, 3: 4}}, nummyPrettyJSON},
 	{"map<string, string>", marshaler,