// Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package jsonpb import ( "encoding/json" "errors" "fmt" "io" "math" "reflect" "strconv" "strings" "time" "github.com/golang/protobuf/proto" "google.golang.org/protobuf/encoding/protojson" protoV2 "google.golang.org/protobuf/proto" "google.golang.org/protobuf/reflect/protoreflect" "google.golang.org/protobuf/reflect/protoregistry" ) const wrapJSONUnmarshalV2 = false // UnmarshalNext unmarshals the next JSON object from d into m. func UnmarshalNext(d *json.Decoder, m proto.Message) error { return new(Unmarshaler).UnmarshalNext(d, m) } // Unmarshal unmarshals a JSON object from r into m. func Unmarshal(r io.Reader, m proto.Message) error { return new(Unmarshaler).Unmarshal(r, m) } // UnmarshalString unmarshals a JSON object from s into m. func UnmarshalString(s string, m proto.Message) error { return new(Unmarshaler).Unmarshal(strings.NewReader(s), m) } // Unmarshaler is a configurable object for converting from a JSON // representation to a protocol buffer object. type Unmarshaler struct { // AllowUnknownFields specifies whether to allow messages to contain // unknown JSON fields, as opposed to failing to unmarshal. AllowUnknownFields bool // AnyResolver is used to resolve the google.protobuf.Any well-known type. // If unset, the global registry is used by default. AnyResolver AnyResolver } // 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. // // The JSON unmarshaling must follow the JSON to proto specification: // // https://developers.google.com/protocol-buffers/docs/proto3#json // // Deprecated: Custom types should implement protobuf reflection instead. type JSONPBUnmarshaler interface { UnmarshalJSONPB(*Unmarshaler, []byte) error } // Unmarshal unmarshals a JSON object from r into m. func (u *Unmarshaler) Unmarshal(r io.Reader, m proto.Message) error { return u.UnmarshalNext(json.NewDecoder(r), m) } // UnmarshalNext unmarshals the next JSON object from d into m. func (u *Unmarshaler) UnmarshalNext(d *json.Decoder, m proto.Message) error { if m == nil { return errors.New("invalid nil message") } // Parse the next JSON object from the stream. raw := json.RawMessage{} if err := d.Decode(&raw); err != nil { return err } // Check for custom unmarshalers first since they may not properly // implement protobuf reflection that the logic below relies on. if jsu, ok := m.(JSONPBUnmarshaler); ok { return jsu.UnmarshalJSONPB(u, raw) } mr := proto.MessageReflect(m) // NOTE: For historical reasons, a top-level null is treated as a noop. // This is incorrect, but kept for compatibility. if string(raw) == "null" && mr.Descriptor().FullName() != "google.protobuf.Value" { return nil } if wrapJSONUnmarshalV2 { // NOTE: If input message is non-empty, we need to preserve merge semantics // of the old jsonpb implementation. These semantics are not supported by // the protobuf JSON specification. isEmpty := true mr.Range(func(protoreflect.FieldDescriptor, protoreflect.Value) bool { isEmpty = false // at least one iteration implies non-empty return false }) if !isEmpty { // Perform unmarshaling into a newly allocated, empty message. mr = mr.New() // Use a defer to copy all unmarshaled fields into the original message. dst := proto.MessageReflect(m) defer mr.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool { dst.Set(fd, v) return true }) } // Unmarshal using the v2 JSON unmarshaler. opts := protojson.UnmarshalOptions{ DiscardUnknown: u.AllowUnknownFields, } if u.AnyResolver != nil { opts.Resolver = anyResolver{u.AnyResolver} } return opts.Unmarshal(raw, mr.Interface()) } else { if err := u.unmarshalMessage(mr, raw); err != nil { return err } return protoV2.CheckInitialized(mr.Interface()) } } func (u *Unmarshaler) unmarshalMessage(m protoreflect.Message, in []byte) error { md := m.Descriptor() fds := md.Fields() if jsu, ok := proto.MessageV1(m.Interface()).(JSONPBUnmarshaler); ok { return jsu.UnmarshalJSONPB(u, in) } if string(in) == "null" && md.FullName() != "google.protobuf.Value" { return nil } switch wellKnownType(md.FullName()) { case "Any": var jsonObject map[string]json.RawMessage if err := json.Unmarshal(in, &jsonObject); err != nil { return err } rawTypeURL, ok := jsonObject["@type"] if !ok { return errors.New("Any JSON doesn't have '@type'") } typeURL, err := unquoteString(string(rawTypeURL)) if err != nil { return fmt.Errorf("can't unmarshal Any's '@type': %q", rawTypeURL) } m.Set(fds.ByNumber(1), protoreflect.ValueOfString(typeURL)) var m2 protoreflect.Message if u.AnyResolver != nil { mi, err := u.AnyResolver.Resolve(typeURL) if err != nil { return err } m2 = proto.MessageReflect(mi) } else { mt, err := protoregistry.GlobalTypes.FindMessageByURL(typeURL) if err != nil { if err == protoregistry.NotFound { return fmt.Errorf("could not resolve Any message type: %v", typeURL) } return err } m2 = mt.New() } if wellKnownType(m2.Descriptor().FullName()) != "" { rawValue, ok := jsonObject["value"] if !ok { return errors.New("Any JSON doesn't have 'value'") } if err := u.unmarshalMessage(m2, rawValue); err != nil { return fmt.Errorf("can't unmarshal Any nested proto %v: %v", typeURL, err) } } else { delete(jsonObject, "@type") rawJSON, err := json.Marshal(jsonObject) if err != nil { return fmt.Errorf("can't generate JSON for Any's nested proto to be unmarshaled: %v", err) } if err = u.unmarshalMessage(m2, rawJSON); err != nil { return fmt.Errorf("can't unmarshal Any nested proto %v: %v", typeURL, err) } } rawWire, err := protoV2.Marshal(m2.Interface()) if err != nil { return fmt.Errorf("can't marshal proto %v into Any.Value: %v", typeURL, err) } m.Set(fds.ByNumber(2), protoreflect.ValueOfBytes(rawWire)) return nil case "BoolValue", "BytesValue", "StringValue", "Int32Value", "UInt32Value", "FloatValue", "Int64Value", "UInt64Value", "DoubleValue": fd := fds.ByNumber(1) v, err := u.unmarshalValue(m.NewField(fd), in, fd) if err != nil { return err } m.Set(fd, v) return nil case "Duration": v, err := unquoteString(string(in)) if err != nil { return err } d, err := time.ParseDuration(v) if err != nil { return fmt.Errorf("bad Duration: %v", err) } sec := d.Nanoseconds() / 1e9 nsec := d.Nanoseconds() % 1e9 m.Set(fds.ByNumber(1), protoreflect.ValueOfInt64(int64(sec))) m.Set(fds.ByNumber(2), protoreflect.ValueOfInt32(int32(nsec))) return nil case "Timestamp": v, err := unquoteString(string(in)) if err != nil { return err } t, err := time.Parse(time.RFC3339Nano, v) if err != nil { return fmt.Errorf("bad Timestamp: %v", err) } sec := t.Unix() nsec := t.Nanosecond() m.Set(fds.ByNumber(1), protoreflect.ValueOfInt64(int64(sec))) m.Set(fds.ByNumber(2), protoreflect.ValueOfInt32(int32(nsec))) return nil case "Value": switch { case string(in) == "null": m.Set(fds.ByNumber(1), protoreflect.ValueOfEnum(0)) case string(in) == "true": m.Set(fds.ByNumber(4), protoreflect.ValueOfBool(true)) case string(in) == "false": m.Set(fds.ByNumber(4), protoreflect.ValueOfBool(false)) case hasPrefixAndSuffix('"', in, '"'): s, err := unquoteString(string(in)) if err != nil { return fmt.Errorf("unrecognized type for Value %q", in) } m.Set(fds.ByNumber(3), protoreflect.ValueOfString(s)) case hasPrefixAndSuffix('[', in, ']'): v := m.Mutable(fds.ByNumber(6)) return u.unmarshalMessage(v.Message(), in) case hasPrefixAndSuffix('{', in, '}'): v := m.Mutable(fds.ByNumber(5)) return u.unmarshalMessage(v.Message(), in) default: f, err := strconv.ParseFloat(string(in), 0) if err != nil { return fmt.Errorf("unrecognized type for Value %q", in) } m.Set(fds.ByNumber(2), protoreflect.ValueOfFloat64(f)) } return nil case "ListValue": var jsonArray []json.RawMessage if err := json.Unmarshal(in, &jsonArray); err != nil { return fmt.Errorf("bad ListValue: %v", err) } lv := m.Mutable(fds.ByNumber(1)).List() for _, raw := range jsonArray { ve := lv.NewElement() if err := u.unmarshalMessage(ve.Message(), raw); err != nil { return err } lv.Append(ve) } return nil case "Struct": var jsonObject map[string]json.RawMessage if err := json.Unmarshal(in, &jsonObject); err != nil { return fmt.Errorf("bad StructValue: %v", err) } mv := m.Mutable(fds.ByNumber(1)).Map() for key, raw := range jsonObject { kv := protoreflect.ValueOf(key).MapKey() vv := mv.NewValue() if err := u.unmarshalMessage(vv.Message(), raw); err != nil { return fmt.Errorf("bad value in StructValue for key %q: %v", key, err) } mv.Set(kv, vv) } return nil } var jsonObject map[string]json.RawMessage if err := json.Unmarshal(in, &jsonObject); err != nil { return err } // Handle known fields. for i := 0; i < fds.Len(); i++ { fd := fds.Get(i) if fd.IsWeak() && fd.Message().IsPlaceholder() { continue // weak reference is not linked in } // Search for any raw JSON value associated with this field. var raw json.RawMessage name := string(fd.Name()) if fd.Kind() == protoreflect.GroupKind { name = string(fd.Message().Name()) } if v, ok := jsonObject[name]; ok { delete(jsonObject, name) raw = v } name = string(fd.JSONName()) if v, ok := jsonObject[name]; ok { delete(jsonObject, name) raw = v } field := m.NewField(fd) // Unmarshal the field value. if raw == nil || (string(raw) == "null" && !isSingularWellKnownValue(fd) && !isSingularJSONPBUnmarshaler(field, fd)) { continue } v, err := u.unmarshalValue(field, raw, fd) if err != nil { return err } m.Set(fd, v) } // Handle extension fields. for name, raw := range jsonObject { if !strings.HasPrefix(name, "[") || !strings.HasSuffix(name, "]") { continue } // Resolve the extension field by name. xname := protoreflect.FullName(name[len("[") : len(name)-len("]")]) xt, _ := protoregistry.GlobalTypes.FindExtensionByName(xname) if xt == nil && isMessageSet(md) { xt, _ = protoregistry.GlobalTypes.FindExtensionByName(xname.Append("message_set_extension")) } if xt == nil { continue } delete(jsonObject, name) fd := xt.TypeDescriptor() if fd.ContainingMessage().FullName() != m.Descriptor().FullName() { return fmt.Errorf("extension field %q does not extend message %q", xname, m.Descriptor().FullName()) } field := m.NewField(fd) // Unmarshal the field value. if raw == nil || (string(raw) == "null" && !isSingularWellKnownValue(fd) && !isSingularJSONPBUnmarshaler(field, fd)) { continue } v, err := u.unmarshalValue(field, raw, fd) if err != nil { return err } m.Set(fd, v) } if !u.AllowUnknownFields && len(jsonObject) > 0 { for name := range jsonObject { return fmt.Errorf("unknown field %q in %v", name, md.FullName()) } } return nil } func isSingularWellKnownValue(fd protoreflect.FieldDescriptor) bool { if fd.Cardinality() == protoreflect.Repeated { return false } if md := fd.Message(); md != nil { return md.FullName() == "google.protobuf.Value" } if ed := fd.Enum(); ed != nil { return ed.FullName() == "google.protobuf.NullValue" } return false } func isSingularJSONPBUnmarshaler(v protoreflect.Value, fd protoreflect.FieldDescriptor) bool { if fd.Message() != nil && fd.Cardinality() != protoreflect.Repeated { _, ok := proto.MessageV1(v.Interface()).(JSONPBUnmarshaler) return ok } return false } func (u *Unmarshaler) unmarshalValue(v protoreflect.Value, in []byte, fd protoreflect.FieldDescriptor) (protoreflect.Value, error) { switch { case fd.IsList(): var jsonArray []json.RawMessage if err := json.Unmarshal(in, &jsonArray); err != nil { return v, err } lv := v.List() for _, raw := range jsonArray { ve, err := u.unmarshalSingularValue(lv.NewElement(), raw, fd) if err != nil { return v, err } lv.Append(ve) } return v, nil case fd.IsMap(): var jsonObject map[string]json.RawMessage if err := json.Unmarshal(in, &jsonObject); err != nil { return v, err } kfd := fd.MapKey() vfd := fd.MapValue() mv := v.Map() for key, raw := range jsonObject { var kv protoreflect.MapKey if kfd.Kind() == protoreflect.StringKind { kv = protoreflect.ValueOf(key).MapKey() } else { v, err := u.unmarshalSingularValue(kfd.Default(), []byte(key), kfd) if err != nil { return v, err } kv = v.MapKey() } vv, err := u.unmarshalSingularValue(mv.NewValue(), raw, vfd) if err != nil { return v, err } mv.Set(kv, vv) } return v, nil default: return u.unmarshalSingularValue(v, in, fd) } } var nonFinite = map[string]float64{ `"NaN"`: math.NaN(), `"Infinity"`: math.Inf(+1), `"-Infinity"`: math.Inf(-1), } func (u *Unmarshaler) unmarshalSingularValue(v protoreflect.Value, in []byte, fd protoreflect.FieldDescriptor) (protoreflect.Value, error) { switch fd.Kind() { case protoreflect.BoolKind: return unmarshalValue(in, new(bool)) case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind: return unmarshalValue(trimQuote(in), new(int32)) case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: return unmarshalValue(trimQuote(in), new(int64)) case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: return unmarshalValue(trimQuote(in), new(uint32)) case protoreflect.Uint64Kind, protoreflect.Fixed64Kind: return unmarshalValue(trimQuote(in), new(uint64)) case protoreflect.FloatKind: if f, ok := nonFinite[string(in)]; ok { return protoreflect.ValueOfFloat32(float32(f)), nil } return unmarshalValue(trimQuote(in), new(float32)) case protoreflect.DoubleKind: if f, ok := nonFinite[string(in)]; ok { return protoreflect.ValueOfFloat64(float64(f)), nil } return unmarshalValue(trimQuote(in), new(float64)) case protoreflect.StringKind: return unmarshalValue(in, new(string)) case protoreflect.BytesKind: return unmarshalValue(in, new([]byte)) case protoreflect.EnumKind: if hasPrefixAndSuffix('"', in, '"') { vd := fd.Enum().Values().ByName(protoreflect.Name(trimQuote(in))) if vd == nil { return v, fmt.Errorf("unknown value %q for enum %s", in, fd.Enum().FullName()) } return protoreflect.ValueOfEnum(vd.Number()), nil } return unmarshalValue(in, new(protoreflect.EnumNumber)) case protoreflect.MessageKind, protoreflect.GroupKind: err := u.unmarshalMessage(v.Message(), in) return v, err default: panic(fmt.Sprintf("invalid kind %v", fd.Kind())) } } func unmarshalValue(in []byte, v interface{}) (protoreflect.Value, error) { err := json.Unmarshal(in, v) return protoreflect.ValueOf(reflect.ValueOf(v).Elem().Interface()), err } func unquoteString(in string) (out string, err error) { err = json.Unmarshal([]byte(in), &out) return out, err } func hasPrefixAndSuffix(prefix byte, in []byte, suffix byte) bool { if len(in) >= 2 && in[0] == prefix && in[len(in)-1] == suffix { return true } return false } // trimQuote is like unquoteString but simply strips surrounding quotes. // This is incorrect, but is behavior done by the legacy implementation. func trimQuote(in []byte) []byte { if len(in) >= 2 && in[0] == '"' && in[len(in)-1] == '"' { in = in[1 : len(in)-1] } return in }