func decodeJSONPb(d *json.Decoder, v interface{}) error { p, ok := v.(proto.Message) if !ok { return decodeNonProtoField(d, v) } return jsonpb.UnmarshalNext(d, p) }
func decodeNonProtoField(d *json.Decoder, v interface{}) error { rv := reflect.ValueOf(v) if rv.Kind() != reflect.Ptr { return fmt.Errorf("%T is not a pointer", v) } for rv.Kind() == reflect.Ptr { if rv.IsNil() { rv.Set(reflect.New(rv.Type().Elem())) } if rv.Type().ConvertibleTo(typeProtoMessage) { return jsonpb.UnmarshalNext(d, rv.Interface().(proto.Message)) } rv = rv.Elem() } if rv.Kind() == reflect.Map { if rv.IsNil() { rv.Set(reflect.MakeMap(rv.Type())) } conv, ok := convFromType[rv.Type().Key().Kind()] if !ok { return fmt.Errorf("unsupported type of map field key: %v", rv.Type().Key()) } m := make(map[string]*json.RawMessage) if err := d.Decode(&m); err != nil { return err } for k, v := range m { result := conv.Call([]reflect.Value{reflect.ValueOf(k)}) if err := result[1].Interface(); err != nil { return err.(error) } bk := result[0] bv := reflect.New(rv.Type().Elem()) if err := unmarshalJSONPb([]byte(*v), bv.Interface()); err != nil { return err } rv.SetMapIndex(bk, bv.Elem()) } return nil } if _, ok := rv.Interface().(protoEnum); ok { var repr interface{} if err := d.Decode(&repr); err != nil { return err } switch repr.(type) { case string: // TODO(yugui) Should use proto.StructProperties? return fmt.Errorf("unmarshaling of symbolic enum %q not supported: %T", repr, rv.Interface()) case float64: rv.Set(reflect.ValueOf(int32(repr.(float64))).Convert(rv.Type())) return nil default: return fmt.Errorf("cannot assign %#v into Go type %T", repr, rv.Interface()) } } return d.Decode(v) }