...

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

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

     1  package runtime
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io"
     8  	"reflect"
     9  
    10  	"github.com/golang/protobuf/jsonpb"
    11  	"github.com/golang/protobuf/proto"
    12  )
    13  
    14  // JSONPb is a Marshaler which marshals/unmarshals into/from JSON
    15  // with the "github.com/golang/protobuf/jsonpb".
    16  // It supports fully functionality of protobuf unlike JSONBuiltin.
    17  //
    18  // The NewDecoder method returns a DecoderWrapper, so the underlying
    19  // *json.Decoder methods can be used.
    20  type JSONPb jsonpb.Marshaler
    21  
    22  // ContentType always returns "application/json".
    23  func (*JSONPb) ContentType() string {
    24  	return "application/json"
    25  }
    26  
    27  // Marshal marshals "v" into JSON.
    28  func (j *JSONPb) Marshal(v interface{}) ([]byte, error) {
    29  	if _, ok := v.(proto.Message); !ok {
    30  		return j.marshalNonProtoField(v)
    31  	}
    32  
    33  	var buf bytes.Buffer
    34  	if err := j.marshalTo(&buf, v); err != nil {
    35  		return nil, err
    36  	}
    37  	return buf.Bytes(), nil
    38  }
    39  
    40  func (j *JSONPb) marshalTo(w io.Writer, v interface{}) error {
    41  	p, ok := v.(proto.Message)
    42  	if !ok {
    43  		buf, err := j.marshalNonProtoField(v)
    44  		if err != nil {
    45  			return err
    46  		}
    47  		_, err = w.Write(buf)
    48  		return err
    49  	}
    50  	return (*jsonpb.Marshaler)(j).Marshal(w, p)
    51  }
    52  
    53  var (
    54  	// protoMessageType is stored to prevent constant lookup of the same type at runtime.
    55  	protoMessageType = reflect.TypeOf((*proto.Message)(nil)).Elem()
    56  )
    57  
    58  // marshalNonProto marshals a non-message field of a protobuf message.
    59  // This function does not correctly marshals arbitrary data structure into JSON,
    60  // but it is only capable of marshaling non-message field values of protobuf,
    61  // i.e. primitive types, enums; pointers to primitives or enums; maps from
    62  // integer/string types to primitives/enums/pointers to messages.
    63  func (j *JSONPb) marshalNonProtoField(v interface{}) ([]byte, error) {
    64  	if v == nil {
    65  		return []byte("null"), nil
    66  	}
    67  	rv := reflect.ValueOf(v)
    68  	for rv.Kind() == reflect.Ptr {
    69  		if rv.IsNil() {
    70  			return []byte("null"), nil
    71  		}
    72  		rv = rv.Elem()
    73  	}
    74  
    75  	if rv.Kind() == reflect.Slice {
    76  		if rv.IsNil() {
    77  			if j.EmitDefaults {
    78  				return []byte("[]"), nil
    79  			}
    80  			return []byte("null"), nil
    81  		}
    82  
    83  		if rv.Type().Elem().Implements(protoMessageType) {
    84  			var buf bytes.Buffer
    85  			err := buf.WriteByte('[')
    86  			if err != nil {
    87  				return nil, err
    88  			}
    89  			for i := 0; i < rv.Len(); i++ {
    90  				if i != 0 {
    91  					err = buf.WriteByte(',')
    92  					if err != nil {
    93  						return nil, err
    94  					}
    95  				}
    96  				if err = (*jsonpb.Marshaler)(j).Marshal(&buf, rv.Index(i).Interface().(proto.Message)); err != nil {
    97  					return nil, err
    98  				}
    99  			}
   100  			err = buf.WriteByte(']')
   101  			if err != nil {
   102  				return nil, err
   103  			}
   104  
   105  			return buf.Bytes(), nil
   106  		}
   107  	}
   108  
   109  	if rv.Kind() == reflect.Map {
   110  		m := make(map[string]*json.RawMessage)
   111  		for _, k := range rv.MapKeys() {
   112  			buf, err := j.Marshal(rv.MapIndex(k).Interface())
   113  			if err != nil {
   114  				return nil, err
   115  			}
   116  			m[fmt.Sprintf("%v", k.Interface())] = (*json.RawMessage)(&buf)
   117  		}
   118  		if j.Indent != "" {
   119  			return json.MarshalIndent(m, "", j.Indent)
   120  		}
   121  		return json.Marshal(m)
   122  	}
   123  	if enum, ok := rv.Interface().(protoEnum); ok && !j.EnumsAsInts {
   124  		return json.Marshal(enum.String())
   125  	}
   126  	return json.Marshal(rv.Interface())
   127  }
   128  
   129  // Unmarshal unmarshals JSON "data" into "v"
   130  func (j *JSONPb) Unmarshal(data []byte, v interface{}) error {
   131  	return unmarshalJSONPb(data, v)
   132  }
   133  
   134  // NewDecoder returns a Decoder which reads JSON stream from "r".
   135  func (j *JSONPb) NewDecoder(r io.Reader) Decoder {
   136  	d := json.NewDecoder(r)
   137  	return DecoderWrapper{Decoder: d}
   138  }
   139  
   140  // DecoderWrapper is a wrapper around a *json.Decoder that adds
   141  // support for protos to the Decode method.
   142  type DecoderWrapper struct {
   143  	*json.Decoder
   144  }
   145  
   146  // Decode wraps the embedded decoder's Decode method to support
   147  // protos using a jsonpb.Unmarshaler.
   148  func (d DecoderWrapper) Decode(v interface{}) error {
   149  	return decodeJSONPb(d.Decoder, v)
   150  }
   151  
   152  // NewEncoder returns an Encoder which writes JSON stream into "w".
   153  func (j *JSONPb) NewEncoder(w io.Writer) Encoder {
   154  	return EncoderFunc(func(v interface{}) error {
   155  		if err := j.marshalTo(w, v); err != nil {
   156  			return err
   157  		}
   158  		// mimic json.Encoder by adding a newline (makes output
   159  		// easier to read when it contains multiple encoded items)
   160  		_, err := w.Write(j.Delimiter())
   161  		return err
   162  	})
   163  }
   164  
   165  func unmarshalJSONPb(data []byte, v interface{}) error {
   166  	d := json.NewDecoder(bytes.NewReader(data))
   167  	return decodeJSONPb(d, v)
   168  }
   169  
   170  func decodeJSONPb(d *json.Decoder, v interface{}) error {
   171  	p, ok := v.(proto.Message)
   172  	if !ok {
   173  		return decodeNonProtoField(d, v)
   174  	}
   175  	unmarshaler := &jsonpb.Unmarshaler{AllowUnknownFields: allowUnknownFields}
   176  	return unmarshaler.UnmarshalNext(d, p)
   177  }
   178  
   179  func decodeNonProtoField(d *json.Decoder, v interface{}) error {
   180  	rv := reflect.ValueOf(v)
   181  	if rv.Kind() != reflect.Ptr {
   182  		return fmt.Errorf("%T is not a pointer", v)
   183  	}
   184  	for rv.Kind() == reflect.Ptr {
   185  		if rv.IsNil() {
   186  			rv.Set(reflect.New(rv.Type().Elem()))
   187  		}
   188  		if rv.Type().ConvertibleTo(typeProtoMessage) {
   189  			unmarshaler := &jsonpb.Unmarshaler{AllowUnknownFields: allowUnknownFields}
   190  			return unmarshaler.UnmarshalNext(d, rv.Interface().(proto.Message))
   191  		}
   192  		rv = rv.Elem()
   193  	}
   194  	if rv.Kind() == reflect.Map {
   195  		if rv.IsNil() {
   196  			rv.Set(reflect.MakeMap(rv.Type()))
   197  		}
   198  		conv, ok := convFromType[rv.Type().Key().Kind()]
   199  		if !ok {
   200  			return fmt.Errorf("unsupported type of map field key: %v", rv.Type().Key())
   201  		}
   202  
   203  		m := make(map[string]*json.RawMessage)
   204  		if err := d.Decode(&m); err != nil {
   205  			return err
   206  		}
   207  		for k, v := range m {
   208  			result := conv.Call([]reflect.Value{reflect.ValueOf(k)})
   209  			if err := result[1].Interface(); err != nil {
   210  				return err.(error)
   211  			}
   212  			bk := result[0]
   213  			bv := reflect.New(rv.Type().Elem())
   214  			if err := unmarshalJSONPb([]byte(*v), bv.Interface()); err != nil {
   215  				return err
   216  			}
   217  			rv.SetMapIndex(bk, bv.Elem())
   218  		}
   219  		return nil
   220  	}
   221  	if _, ok := rv.Interface().(protoEnum); ok {
   222  		var repr interface{}
   223  		if err := d.Decode(&repr); err != nil {
   224  			return err
   225  		}
   226  		switch repr.(type) {
   227  		case string:
   228  			// TODO(yugui) Should use proto.StructProperties?
   229  			return fmt.Errorf("unmarshaling of symbolic enum %q not supported: %T", repr, rv.Interface())
   230  		case float64:
   231  			rv.Set(reflect.ValueOf(int32(repr.(float64))).Convert(rv.Type()))
   232  			return nil
   233  		default:
   234  			return fmt.Errorf("cannot assign %#v into Go type %T", repr, rv.Interface())
   235  		}
   236  	}
   237  	return d.Decode(v)
   238  }
   239  
   240  type protoEnum interface {
   241  	fmt.Stringer
   242  	EnumDescriptor() ([]byte, []int)
   243  }
   244  
   245  var typeProtoMessage = reflect.TypeOf((*proto.Message)(nil)).Elem()
   246  
   247  // Delimiter for newline encoded JSON streams.
   248  func (j *JSONPb) Delimiter() []byte {
   249  	return []byte("\n")
   250  }
   251  
   252  // allowUnknownFields helps not to return an error when the destination
   253  // is a struct and the input contains object keys which do not match any
   254  // non-ignored, exported fields in the destination.
   255  var allowUnknownFields = true
   256  
   257  // DisallowUnknownFields enables option in decoder (unmarshaller) to
   258  // return an error when it finds an unknown field. This function must be
   259  // called before using the JSON marshaller.
   260  func DisallowUnknownFields() {
   261  	allowUnknownFields = false
   262  }
   263  

View as plain text