...

Source file src/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/marshal_jsonpb.go

Documentation: github.com/grpc-ecosystem/grpc-gateway/v2/runtime

     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  			if err := buf.WriteByte('['); err != nil {
    96  				return nil, err
    97  			}
    98  			for i := 0; i < rv.Len(); i++ {
    99  				if i != 0 {
   100  					if err := buf.WriteByte(','); err != nil {
   101  						return nil, err
   102  					}
   103  				}
   104  				if err := j.marshalTo(&buf, rv.Index(i).Interface().(proto.Message)); err != nil {
   105  					return nil, err
   106  				}
   107  			}
   108  			if err := buf.WriteByte(']'); err != nil {
   109  				return nil, err
   110  			}
   111  
   112  			return buf.Bytes(), nil
   113  		}
   114  
   115  		if rv.Type().Elem().Implements(typeProtoEnum) {
   116  			var buf bytes.Buffer
   117  			if err := buf.WriteByte('['); err != nil {
   118  				return nil, err
   119  			}
   120  			for i := 0; i < rv.Len(); i++ {
   121  				if i != 0 {
   122  					if err := buf.WriteByte(','); err != nil {
   123  						return nil, err
   124  					}
   125  				}
   126  				var err error
   127  				if j.UseEnumNumbers {
   128  					_, err = buf.WriteString(strconv.FormatInt(rv.Index(i).Int(), 10))
   129  				} else {
   130  					_, err = buf.WriteString("\"" + rv.Index(i).Interface().(protoEnum).String() + "\"")
   131  				}
   132  				if err != nil {
   133  					return nil, err
   134  				}
   135  			}
   136  			if err := buf.WriteByte(']'); err != nil {
   137  				return nil, err
   138  			}
   139  
   140  			return buf.Bytes(), nil
   141  		}
   142  	}
   143  
   144  	if rv.Kind() == reflect.Map {
   145  		m := make(map[string]*json.RawMessage)
   146  		for _, k := range rv.MapKeys() {
   147  			buf, err := j.Marshal(rv.MapIndex(k).Interface())
   148  			if err != nil {
   149  				return nil, err
   150  			}
   151  			m[fmt.Sprintf("%v", k.Interface())] = (*json.RawMessage)(&buf)
   152  		}
   153  		if j.Indent != "" {
   154  			return json.MarshalIndent(m, "", j.Indent)
   155  		}
   156  		return json.Marshal(m)
   157  	}
   158  	if enum, ok := rv.Interface().(protoEnum); ok && !j.UseEnumNumbers {
   159  		return json.Marshal(enum.String())
   160  	}
   161  	return json.Marshal(rv.Interface())
   162  }
   163  
   164  // Unmarshal unmarshals JSON "data" into "v"
   165  func (j *JSONPb) Unmarshal(data []byte, v interface{}) error {
   166  	return unmarshalJSONPb(data, j.UnmarshalOptions, v)
   167  }
   168  
   169  // NewDecoder returns a Decoder which reads JSON stream from "r".
   170  func (j *JSONPb) NewDecoder(r io.Reader) Decoder {
   171  	d := json.NewDecoder(r)
   172  	return DecoderWrapper{
   173  		Decoder:          d,
   174  		UnmarshalOptions: j.UnmarshalOptions,
   175  	}
   176  }
   177  
   178  // DecoderWrapper is a wrapper around a *json.Decoder that adds
   179  // support for protos to the Decode method.
   180  type DecoderWrapper struct {
   181  	*json.Decoder
   182  	protojson.UnmarshalOptions
   183  }
   184  
   185  // Decode wraps the embedded decoder's Decode method to support
   186  // protos using a jsonpb.Unmarshaler.
   187  func (d DecoderWrapper) Decode(v interface{}) error {
   188  	return decodeJSONPb(d.Decoder, d.UnmarshalOptions, v)
   189  }
   190  
   191  // NewEncoder returns an Encoder which writes JSON stream into "w".
   192  func (j *JSONPb) NewEncoder(w io.Writer) Encoder {
   193  	return EncoderFunc(func(v interface{}) error {
   194  		if err := j.marshalTo(w, v); err != nil {
   195  			return err
   196  		}
   197  		// mimic json.Encoder by adding a newline (makes output
   198  		// easier to read when it contains multiple encoded items)
   199  		_, err := w.Write(j.Delimiter())
   200  		return err
   201  	})
   202  }
   203  
   204  func unmarshalJSONPb(data []byte, unmarshaler protojson.UnmarshalOptions, v interface{}) error {
   205  	d := json.NewDecoder(bytes.NewReader(data))
   206  	return decodeJSONPb(d, unmarshaler, v)
   207  }
   208  
   209  func decodeJSONPb(d *json.Decoder, unmarshaler protojson.UnmarshalOptions, v interface{}) error {
   210  	p, ok := v.(proto.Message)
   211  	if !ok {
   212  		return decodeNonProtoField(d, unmarshaler, v)
   213  	}
   214  
   215  	// Decode into bytes for marshalling
   216  	var b json.RawMessage
   217  	if err := d.Decode(&b); err != nil {
   218  		return err
   219  	}
   220  
   221  	return unmarshaler.Unmarshal([]byte(b), p)
   222  }
   223  
   224  func decodeNonProtoField(d *json.Decoder, unmarshaler protojson.UnmarshalOptions, v interface{}) error {
   225  	rv := reflect.ValueOf(v)
   226  	if rv.Kind() != reflect.Ptr {
   227  		return fmt.Errorf("%T is not a pointer", v)
   228  	}
   229  	for rv.Kind() == reflect.Ptr {
   230  		if rv.IsNil() {
   231  			rv.Set(reflect.New(rv.Type().Elem()))
   232  		}
   233  		if rv.Type().ConvertibleTo(typeProtoMessage) {
   234  			// Decode into bytes for marshalling
   235  			var b json.RawMessage
   236  			if err := d.Decode(&b); err != nil {
   237  				return err
   238  			}
   239  
   240  			return unmarshaler.Unmarshal([]byte(b), rv.Interface().(proto.Message))
   241  		}
   242  		rv = rv.Elem()
   243  	}
   244  	if rv.Kind() == reflect.Map {
   245  		if rv.IsNil() {
   246  			rv.Set(reflect.MakeMap(rv.Type()))
   247  		}
   248  		conv, ok := convFromType[rv.Type().Key().Kind()]
   249  		if !ok {
   250  			return fmt.Errorf("unsupported type of map field key: %v", rv.Type().Key())
   251  		}
   252  
   253  		m := make(map[string]*json.RawMessage)
   254  		if err := d.Decode(&m); err != nil {
   255  			return err
   256  		}
   257  		for k, v := range m {
   258  			result := conv.Call([]reflect.Value{reflect.ValueOf(k)})
   259  			if err := result[1].Interface(); err != nil {
   260  				return err.(error)
   261  			}
   262  			bk := result[0]
   263  			bv := reflect.New(rv.Type().Elem())
   264  			if v == nil {
   265  				null := json.RawMessage("null")
   266  				v = &null
   267  			}
   268  			if err := unmarshalJSONPb([]byte(*v), unmarshaler, bv.Interface()); err != nil {
   269  				return err
   270  			}
   271  			rv.SetMapIndex(bk, bv.Elem())
   272  		}
   273  		return nil
   274  	}
   275  	if rv.Kind() == reflect.Slice {
   276  		if rv.Type().Elem().Kind() == reflect.Uint8 {
   277  			var sl []byte
   278  			if err := d.Decode(&sl); err != nil {
   279  				return err
   280  			}
   281  			if sl != nil {
   282  				rv.SetBytes(sl)
   283  			}
   284  			return nil
   285  		}
   286  
   287  		var sl []json.RawMessage
   288  		if err := d.Decode(&sl); err != nil {
   289  			return err
   290  		}
   291  		if sl != nil {
   292  			rv.Set(reflect.MakeSlice(rv.Type(), 0, 0))
   293  		}
   294  		for _, item := range sl {
   295  			bv := reflect.New(rv.Type().Elem())
   296  			if err := unmarshalJSONPb([]byte(item), unmarshaler, bv.Interface()); err != nil {
   297  				return err
   298  			}
   299  			rv.Set(reflect.Append(rv, bv.Elem()))
   300  		}
   301  		return nil
   302  	}
   303  	if _, ok := rv.Interface().(protoEnum); ok {
   304  		var repr interface{}
   305  		if err := d.Decode(&repr); err != nil {
   306  			return err
   307  		}
   308  		switch v := repr.(type) {
   309  		case string:
   310  			// TODO(yugui) Should use proto.StructProperties?
   311  			return fmt.Errorf("unmarshaling of symbolic enum %q not supported: %T", repr, rv.Interface())
   312  		case float64:
   313  			rv.Set(reflect.ValueOf(int32(v)).Convert(rv.Type()))
   314  			return nil
   315  		default:
   316  			return fmt.Errorf("cannot assign %#v into Go type %T", repr, rv.Interface())
   317  		}
   318  	}
   319  	return d.Decode(v)
   320  }
   321  
   322  type protoEnum interface {
   323  	fmt.Stringer
   324  	EnumDescriptor() ([]byte, []int)
   325  }
   326  
   327  var typeProtoEnum = reflect.TypeOf((*protoEnum)(nil)).Elem()
   328  
   329  var typeProtoMessage = reflect.TypeOf((*proto.Message)(nil)).Elem()
   330  
   331  // Delimiter for newline encoded JSON streams.
   332  func (j *JSONPb) Delimiter() []byte {
   333  	return []byte("\n")
   334  }
   335  
   336  var (
   337  	convFromType = map[reflect.Kind]reflect.Value{
   338  		reflect.String:  reflect.ValueOf(String),
   339  		reflect.Bool:    reflect.ValueOf(Bool),
   340  		reflect.Float64: reflect.ValueOf(Float64),
   341  		reflect.Float32: reflect.ValueOf(Float32),
   342  		reflect.Int64:   reflect.ValueOf(Int64),
   343  		reflect.Int32:   reflect.ValueOf(Int32),
   344  		reflect.Uint64:  reflect.ValueOf(Uint64),
   345  		reflect.Uint32:  reflect.ValueOf(Uint32),
   346  		reflect.Slice:   reflect.ValueOf(Bytes),
   347  	}
   348  )
   349  

View as plain text