func()

in jsonpb/decode.go [134:386]


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
}