diff options
Diffstat (limited to 'vendor/github.com/golang/protobuf/jsonpb/jsonpb.go')
-rw-r--r-- | vendor/github.com/golang/protobuf/jsonpb/jsonpb.go | 117 |
1 files changed, 101 insertions, 16 deletions
diff --git a/vendor/github.com/golang/protobuf/jsonpb/jsonpb.go b/vendor/github.com/golang/protobuf/jsonpb/jsonpb.go index eff41c2e6..c7a45d6f0 100644 --- a/vendor/github.com/golang/protobuf/jsonpb/jsonpb.go +++ b/vendor/github.com/golang/protobuf/jsonpb/jsonpb.go @@ -44,6 +44,7 @@ import ( "errors" "fmt" "io" + "math" "reflect" "sort" "strconv" @@ -74,6 +75,22 @@ type Marshaler struct { OrigName bool } +// JSONPBMarshaler is implemented by protobuf messages that customize the +// way they are marshaled to JSON. Messages that implement this should +// also implement JSONPBUnmarshaler so that the custom format can be +// parsed. +type JSONPBMarshaler interface { + MarshalJSONPB(*Marshaler) ([]byte, error) +} + +// JSONPBUnmarshaler is implemented by protobuf messages that customize +// the way they are unmarshaled from JSON. Messages that implement this +// should also implement JSONPBMarshaler so that the custom format can be +// produced. +type JSONPBUnmarshaler interface { + UnmarshalJSONPB(*Unmarshaler, []byte) error +} + // Marshal marshals a protocol buffer into JSON. func (m *Marshaler) Marshal(out io.Writer, pb proto.Message) error { writer := &errWriter{writer: out} @@ -91,6 +108,12 @@ func (m *Marshaler) MarshalToString(pb proto.Message) (string, error) { type int32Slice []int32 +var nonFinite = map[string]float64{ + `"NaN"`: math.NaN(), + `"Infinity"`: math.Inf(1), + `"-Infinity"`: math.Inf(-1), +} + // For sorting extensions ids to ensure stable output. func (s int32Slice) Len() int { return len(s) } func (s int32Slice) Less(i, j int) bool { return s[i] < s[j] } @@ -102,6 +125,31 @@ type wkt interface { // marshalObject writes a struct to the Writer. func (m *Marshaler) marshalObject(out *errWriter, v proto.Message, indent, typeURL string) error { + if jsm, ok := v.(JSONPBMarshaler); ok { + b, err := jsm.MarshalJSONPB(m) + if err != nil { + return err + } + if typeURL != "" { + // we are marshaling this object to an Any type + var js map[string]*json.RawMessage + if err = json.Unmarshal(b, &js); err != nil { + return fmt.Errorf("type %T produced invalid JSON: %v", v, err) + } + turl, err := json.Marshal(typeURL) + if err != nil { + return fmt.Errorf("failed to marshal type URL %q to JSON: %v", typeURL, err) + } + js["@type"] = (*json.RawMessage)(&turl) + if b, err = json.Marshal(js); err != nil { + return err + } + } + + out.write(string(b)) + return out.err + } + s := reflect.ValueOf(v).Elem() // Handle well-known types. @@ -182,7 +230,7 @@ func (m *Marshaler) marshalObject(out *errWriter, v proto.Message, indent, typeU // IsNil will panic on most value kinds. switch value.Kind() { - case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: + case reflect.Chan, reflect.Func, reflect.Interface: if value.IsNil() { continue } @@ -210,6 +258,10 @@ func (m *Marshaler) marshalObject(out *errWriter, v proto.Message, indent, typeU if value.Len() == 0 { continue } + case reflect.Map, reflect.Ptr, reflect.Slice: + if value.IsNil() { + continue + } } } @@ -373,10 +425,15 @@ func (m *Marshaler) marshalField(out *errWriter, prop *proto.Properties, v refle // marshalValue writes the value to the Writer. func (m *Marshaler) marshalValue(out *errWriter, prop *proto.Properties, v reflect.Value, indent string) error { - var err error v = reflect.Indirect(v) + // Handle nil pointer + if v.Kind() == reflect.Invalid { + out.write("null") + return out.err + } + // Handle repeated elements. if v.Kind() == reflect.Slice && v.Type().Elem().Kind() != reflect.Uint8 { out.write("[") @@ -406,9 +463,6 @@ func (m *Marshaler) marshalValue(out *errWriter, prop *proto.Properties, v refle // Handle well-known types. // Most are handled up in marshalObject (because 99% are messages). - type wkt interface { - XXX_WellKnownType() string - } if wkt, ok := v.Interface().(wkt); ok { switch wkt.XXX_WellKnownType() { case "NullValue": @@ -496,6 +550,24 @@ func (m *Marshaler) marshalValue(out *errWriter, prop *proto.Properties, v refle return out.err } + // Handle non-finite floats, e.g. NaN, Infinity and -Infinity. + if v.Kind() == reflect.Float32 || v.Kind() == reflect.Float64 { + f := v.Float() + var sval string + switch { + case math.IsInf(f, 1): + sval = `"Infinity"` + case math.IsInf(f, -1): + sval = `"-Infinity"` + case math.IsNaN(f): + sval = `"NaN"` + } + if sval != "" { + out.write(sval) + return out.err + } + } + // Default handling defers to the encoding/json library. b, err := json.Marshal(v.Interface()) if err != nil { @@ -571,10 +643,11 @@ func (u *Unmarshaler) unmarshalValue(target reflect.Value, inputValue json.RawMe return u.unmarshalValue(target.Elem(), inputValue, prop) } - // Handle well-known types. - type wkt interface { - XXX_WellKnownType() string + if jsu, ok := target.Addr().Interface().(JSONPBUnmarshaler); ok { + return jsu.UnmarshalJSONPB(u, []byte(inputValue)) } + + // Handle well-known types. if w, ok := target.Addr().Interface().(wkt); ok { switch w.XXX_WellKnownType() { case "DoubleValue", "FloatValue", "Int64Value", "UInt64Value", @@ -585,19 +658,22 @@ func (u *Unmarshaler) unmarshalValue(target reflect.Value, inputValue json.RawMe // so we don't have to do any extra work. return u.unmarshalValue(target.Field(0), inputValue, prop) case "Any": - var jsonFields map[string]json.RawMessage + // Use json.RawMessage pointer type instead of value to support pre-1.8 version. + // 1.8 changed RawMessage.MarshalJSON from pointer type to value type, see + // https://github.com/golang/go/issues/14493 + var jsonFields map[string]*json.RawMessage if err := json.Unmarshal(inputValue, &jsonFields); err != nil { return err } val, ok := jsonFields["@type"] - if !ok { + if !ok || val == nil { return errors.New("Any JSON doesn't have '@type'") } var turl string - if err := json.Unmarshal([]byte(val), &turl); err != nil { - return fmt.Errorf("can't unmarshal Any's '@type': %q", val) + if err := json.Unmarshal([]byte(*val), &turl); err != nil { + return fmt.Errorf("can't unmarshal Any's '@type': %q", *val) } target.Field(0).SetString(turl) @@ -617,8 +693,8 @@ func (u *Unmarshaler) unmarshalValue(target reflect.Value, inputValue json.RawMe return errors.New("Any JSON doesn't have 'value'") } - if err := u.unmarshalValue(reflect.ValueOf(m).Elem(), val, nil); err != nil { - return fmt.Errorf("can't unmarshal Any's WKT: %v", err) + if err := u.unmarshalValue(reflect.ValueOf(m).Elem(), *val, nil); err != nil { + return fmt.Errorf("can't unmarshal Any nested proto %T: %v", m, err) } } else { delete(jsonFields, "@type") @@ -628,13 +704,13 @@ func (u *Unmarshaler) unmarshalValue(target reflect.Value, inputValue json.RawMe } if err = u.unmarshalValue(reflect.ValueOf(m).Elem(), nestedProto, nil); err != nil { - return fmt.Errorf("can't unmarshal nested Any proto: %v", err) + return fmt.Errorf("can't unmarshal Any nested proto %T: %v", m, err) } } b, err := proto.Marshal(m) if err != nil { - return fmt.Errorf("can't marshal proto into Any.Value: %v", err) + return fmt.Errorf("can't marshal proto %T into Any.Value: %v", m, err) } target.Field(1).SetBytes(b) @@ -911,6 +987,15 @@ func (u *Unmarshaler) unmarshalValue(target reflect.Value, inputValue json.RawMe inputValue = inputValue[1 : len(inputValue)-1] } + // Non-finite numbers can be encoded as strings. + isFloat := targetType.Kind() == reflect.Float32 || targetType.Kind() == reflect.Float64 + if isFloat { + if num, ok := nonFinite[string(inputValue)]; ok { + target.SetFloat(num) + return nil + } + } + // Use the encoding/json for parsing other value types. return json.Unmarshal(inputValue, target.Addr().Interface()) } |