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 )