gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

marshal_jsonpb.go (8741B)


      1 package runtime
      2 
      3 import (
      4 	"bytes"
      5 	"encoding/json"
      6 	"fmt"
      7 	"io"
      8 	"reflect"
      9 	"strconv"
     10 
     11 	"google.golang.org/protobuf/encoding/protojson"
     12 	"google.golang.org/protobuf/proto"
     13 )
     14 
     15 // JSONPb is a Marshaler which marshals/unmarshals into/from JSON
     16 // with the "google.golang.org/protobuf/encoding/protojson" marshaler.
     17 // It supports the full functionality of protobuf unlike JSONBuiltin.
     18 //
     19 // The NewDecoder method returns a DecoderWrapper, so the underlying
     20 // *json.Decoder methods can be used.
     21 type JSONPb struct {
     22 	protojson.MarshalOptions
     23 	protojson.UnmarshalOptions
     24 }
     25 
     26 // ContentType always returns "application/json".
     27 func (*JSONPb) ContentType(_ interface{}) string {
     28 	return "application/json"
     29 }
     30 
     31 // Marshal marshals "v" into JSON.
     32 func (j *JSONPb) Marshal(v interface{}) ([]byte, error) {
     33 	if _, ok := v.(proto.Message); !ok {
     34 		return j.marshalNonProtoField(v)
     35 	}
     36 
     37 	var buf bytes.Buffer
     38 	if err := j.marshalTo(&buf, v); err != nil {
     39 		return nil, err
     40 	}
     41 	return buf.Bytes(), nil
     42 }
     43 
     44 func (j *JSONPb) marshalTo(w io.Writer, v interface{}) error {
     45 	p, ok := v.(proto.Message)
     46 	if !ok {
     47 		buf, err := j.marshalNonProtoField(v)
     48 		if err != nil {
     49 			return err
     50 		}
     51 		_, err = w.Write(buf)
     52 		return err
     53 	}
     54 	b, err := j.MarshalOptions.Marshal(p)
     55 	if err != nil {
     56 		return err
     57 	}
     58 
     59 	_, err = w.Write(b)
     60 	return err
     61 }
     62 
     63 var (
     64 	// protoMessageType is stored to prevent constant lookup of the same type at runtime.
     65 	protoMessageType = reflect.TypeOf((*proto.Message)(nil)).Elem()
     66 )
     67 
     68 // marshalNonProto marshals a non-message field of a protobuf message.
     69 // This function does not correctly marshal arbitrary data structures into JSON,
     70 // it is only capable of marshaling non-message field values of protobuf,
     71 // i.e. primitive types, enums; pointers to primitives or enums; maps from
     72 // integer/string types to primitives/enums/pointers to messages.
     73 func (j *JSONPb) marshalNonProtoField(v interface{}) ([]byte, error) {
     74 	if v == nil {
     75 		return []byte("null"), nil
     76 	}
     77 	rv := reflect.ValueOf(v)
     78 	for rv.Kind() == reflect.Ptr {
     79 		if rv.IsNil() {
     80 			return []byte("null"), nil
     81 		}
     82 		rv = rv.Elem()
     83 	}
     84 
     85 	if rv.Kind() == reflect.Slice {
     86 		if rv.IsNil() {
     87 			if j.EmitUnpopulated {
     88 				return []byte("[]"), nil
     89 			}
     90 			return []byte("null"), nil
     91 		}
     92 
     93 		if rv.Type().Elem().Implements(protoMessageType) {
     94 			var buf bytes.Buffer
     95 			err := buf.WriteByte('[')
     96 			if err != nil {
     97 				return nil, err
     98 			}
     99 			for i := 0; i < rv.Len(); i++ {
    100 				if i != 0 {
    101 					err = buf.WriteByte(',')
    102 					if err != nil {
    103 						return nil, err
    104 					}
    105 				}
    106 				if err = j.marshalTo(&buf, rv.Index(i).Interface().(proto.Message)); err != nil {
    107 					return nil, err
    108 				}
    109 			}
    110 			err = buf.WriteByte(']')
    111 			if err != nil {
    112 				return nil, err
    113 			}
    114 
    115 			return buf.Bytes(), nil
    116 		}
    117 
    118 		if rv.Type().Elem().Implements(typeProtoEnum) {
    119 			var buf bytes.Buffer
    120 			err := buf.WriteByte('[')
    121 			if err != nil {
    122 				return nil, err
    123 			}
    124 			for i := 0; i < rv.Len(); i++ {
    125 				if i != 0 {
    126 					err = buf.WriteByte(',')
    127 					if err != nil {
    128 						return nil, err
    129 					}
    130 				}
    131 				if j.UseEnumNumbers {
    132 					_, err = buf.WriteString(strconv.FormatInt(rv.Index(i).Int(), 10))
    133 				} else {
    134 					_, err = buf.WriteString("\"" + rv.Index(i).Interface().(protoEnum).String() + "\"")
    135 				}
    136 				if err != nil {
    137 					return nil, err
    138 				}
    139 			}
    140 			err = buf.WriteByte(']')
    141 			if err != nil {
    142 				return nil, err
    143 			}
    144 
    145 			return buf.Bytes(), nil
    146 		}
    147 	}
    148 
    149 	if rv.Kind() == reflect.Map {
    150 		m := make(map[string]*json.RawMessage)
    151 		for _, k := range rv.MapKeys() {
    152 			buf, err := j.Marshal(rv.MapIndex(k).Interface())
    153 			if err != nil {
    154 				return nil, err
    155 			}
    156 			m[fmt.Sprintf("%v", k.Interface())] = (*json.RawMessage)(&buf)
    157 		}
    158 		if j.Indent != "" {
    159 			return json.MarshalIndent(m, "", j.Indent)
    160 		}
    161 		return json.Marshal(m)
    162 	}
    163 	if enum, ok := rv.Interface().(protoEnum); ok && !j.UseEnumNumbers {
    164 		return json.Marshal(enum.String())
    165 	}
    166 	return json.Marshal(rv.Interface())
    167 }
    168 
    169 // Unmarshal unmarshals JSON "data" into "v"
    170 func (j *JSONPb) Unmarshal(data []byte, v interface{}) error {
    171 	return unmarshalJSONPb(data, j.UnmarshalOptions, v)
    172 }
    173 
    174 // NewDecoder returns a Decoder which reads JSON stream from "r".
    175 func (j *JSONPb) NewDecoder(r io.Reader) Decoder {
    176 	d := json.NewDecoder(r)
    177 	return DecoderWrapper{
    178 		Decoder:          d,
    179 		UnmarshalOptions: j.UnmarshalOptions,
    180 	}
    181 }
    182 
    183 // DecoderWrapper is a wrapper around a *json.Decoder that adds
    184 // support for protos to the Decode method.
    185 type DecoderWrapper struct {
    186 	*json.Decoder
    187 	protojson.UnmarshalOptions
    188 }
    189 
    190 // Decode wraps the embedded decoder's Decode method to support
    191 // protos using a jsonpb.Unmarshaler.
    192 func (d DecoderWrapper) Decode(v interface{}) error {
    193 	return decodeJSONPb(d.Decoder, d.UnmarshalOptions, v)
    194 }
    195 
    196 // NewEncoder returns an Encoder which writes JSON stream into "w".
    197 func (j *JSONPb) NewEncoder(w io.Writer) Encoder {
    198 	return EncoderFunc(func(v interface{}) error {
    199 		if err := j.marshalTo(w, v); err != nil {
    200 			return err
    201 		}
    202 		// mimic json.Encoder by adding a newline (makes output
    203 		// easier to read when it contains multiple encoded items)
    204 		_, err := w.Write(j.Delimiter())
    205 		return err
    206 	})
    207 }
    208 
    209 func unmarshalJSONPb(data []byte, unmarshaler protojson.UnmarshalOptions, v interface{}) error {
    210 	d := json.NewDecoder(bytes.NewReader(data))
    211 	return decodeJSONPb(d, unmarshaler, v)
    212 }
    213 
    214 func decodeJSONPb(d *json.Decoder, unmarshaler protojson.UnmarshalOptions, v interface{}) error {
    215 	p, ok := v.(proto.Message)
    216 	if !ok {
    217 		return decodeNonProtoField(d, unmarshaler, v)
    218 	}
    219 
    220 	// Decode into bytes for marshalling
    221 	var b json.RawMessage
    222 	err := d.Decode(&b)
    223 	if err != nil {
    224 		return err
    225 	}
    226 
    227 	return unmarshaler.Unmarshal([]byte(b), p)
    228 }
    229 
    230 func decodeNonProtoField(d *json.Decoder, unmarshaler protojson.UnmarshalOptions, v interface{}) error {
    231 	rv := reflect.ValueOf(v)
    232 	if rv.Kind() != reflect.Ptr {
    233 		return fmt.Errorf("%T is not a pointer", v)
    234 	}
    235 	for rv.Kind() == reflect.Ptr {
    236 		if rv.IsNil() {
    237 			rv.Set(reflect.New(rv.Type().Elem()))
    238 		}
    239 		if rv.Type().ConvertibleTo(typeProtoMessage) {
    240 			// Decode into bytes for marshalling
    241 			var b json.RawMessage
    242 			err := d.Decode(&b)
    243 			if err != nil {
    244 				return err
    245 			}
    246 
    247 			return unmarshaler.Unmarshal([]byte(b), rv.Interface().(proto.Message))
    248 		}
    249 		rv = rv.Elem()
    250 	}
    251 	if rv.Kind() == reflect.Map {
    252 		if rv.IsNil() {
    253 			rv.Set(reflect.MakeMap(rv.Type()))
    254 		}
    255 		conv, ok := convFromType[rv.Type().Key().Kind()]
    256 		if !ok {
    257 			return fmt.Errorf("unsupported type of map field key: %v", rv.Type().Key())
    258 		}
    259 
    260 		m := make(map[string]*json.RawMessage)
    261 		if err := d.Decode(&m); err != nil {
    262 			return err
    263 		}
    264 		for k, v := range m {
    265 			result := conv.Call([]reflect.Value{reflect.ValueOf(k)})
    266 			if err := result[1].Interface(); err != nil {
    267 				return err.(error)
    268 			}
    269 			bk := result[0]
    270 			bv := reflect.New(rv.Type().Elem())
    271 			if v == nil {
    272 				null := json.RawMessage("null")
    273 				v = &null
    274 			}
    275 			if err := unmarshalJSONPb([]byte(*v), unmarshaler, bv.Interface()); err != nil {
    276 				return err
    277 			}
    278 			rv.SetMapIndex(bk, bv.Elem())
    279 		}
    280 		return nil
    281 	}
    282 	if rv.Kind() == reflect.Slice {
    283 		var sl []json.RawMessage
    284 		if err := d.Decode(&sl); err != nil {
    285 			return err
    286 		}
    287 		if sl != nil {
    288 			rv.Set(reflect.MakeSlice(rv.Type(), 0, 0))
    289 		}
    290 		for _, item := range sl {
    291 			bv := reflect.New(rv.Type().Elem())
    292 			if err := unmarshalJSONPb([]byte(item), unmarshaler, bv.Interface()); err != nil {
    293 				return err
    294 			}
    295 			rv.Set(reflect.Append(rv, bv.Elem()))
    296 		}
    297 		return nil
    298 	}
    299 	if _, ok := rv.Interface().(protoEnum); ok {
    300 		var repr interface{}
    301 		if err := d.Decode(&repr); err != nil {
    302 			return err
    303 		}
    304 		switch v := repr.(type) {
    305 		case string:
    306 			// TODO(yugui) Should use proto.StructProperties?
    307 			return fmt.Errorf("unmarshaling of symbolic enum %q not supported: %T", repr, rv.Interface())
    308 		case float64:
    309 			rv.Set(reflect.ValueOf(int32(v)).Convert(rv.Type()))
    310 			return nil
    311 		default:
    312 			return fmt.Errorf("cannot assign %#v into Go type %T", repr, rv.Interface())
    313 		}
    314 	}
    315 	return d.Decode(v)
    316 }
    317 
    318 type protoEnum interface {
    319 	fmt.Stringer
    320 	EnumDescriptor() ([]byte, []int)
    321 }
    322 
    323 var typeProtoEnum = reflect.TypeOf((*protoEnum)(nil)).Elem()
    324 
    325 var typeProtoMessage = reflect.TypeOf((*proto.Message)(nil)).Elem()
    326 
    327 // Delimiter for newline encoded JSON streams.
    328 func (j *JSONPb) Delimiter() []byte {
    329 	return []byte("\n")
    330 }
    331 
    332 var (
    333 	convFromType = map[reflect.Kind]reflect.Value{
    334 		reflect.String:  reflect.ValueOf(String),
    335 		reflect.Bool:    reflect.ValueOf(Bool),
    336 		reflect.Float64: reflect.ValueOf(Float64),
    337 		reflect.Float32: reflect.ValueOf(Float32),
    338 		reflect.Int64:   reflect.ValueOf(Int64),
    339 		reflect.Int32:   reflect.ValueOf(Int32),
    340 		reflect.Uint64:  reflect.ValueOf(Uint64),
    341 		reflect.Uint32:  reflect.ValueOf(Uint32),
    342 		reflect.Slice:   reflect.ValueOf(Bytes),
    343 	}
    344 )