From 27796c1b09cfaa1e75d368fb87d070eacd2f7e3b Mon Sep 17 00:00:00 2001 From: Yuki Yugui Sonoda Date: Mon, 9 May 2016 11:29:48 +0900 Subject: [PATCH 1/4] Fix style and lint errors --- runtime/marshaler.go | 124 ++++++++++++++++++++++++++++--------------- 1 file changed, 80 insertions(+), 44 deletions(-) diff --git a/runtime/marshaler.go b/runtime/marshaler.go index a2112776526..b250d33ec03 100644 --- a/runtime/marshaler.go +++ b/runtime/marshaler.go @@ -11,23 +11,25 @@ import ( "github.com/golang/protobuf/proto" ) -const MIMEWILDCARD = "*" +const mimeWildcard = "*" -var inboundDefaultMarshaler = &JSONBuiltin{} -var outboundDefaultMarshaler = &JSONBuiltin{} -var contentTypeHeader = http.CanonicalHeaderKey("Content-Type") +var ( + inboundDefaultMarshaler = new(JSONBuiltin) + outboundDefaultMarshaler = new(JSONBuiltin) -// Get the inbound/outbound marshalers for this request. Checks the registry on the ServeMux for -// the MIME type set by the Content-Type header. + contentTypeHeader = http.CanonicalHeaderKey("Content-Type") +) + +// MarshalerForRequest returns the inbound/outbound marshalers for this request. +// It checks the registry on the ServeMux for the MIME type set by the Content-Type header. // If it isn't set (or the request Content-Type is empty), checks for "*". // If that isn't set, uses the ServerMux's InboundMarshaler/OutboundMarshaler. // If there are multiple Content-Type headers set, choose the first one that it can -// exactly match in the registry. Otherwise, follows the above logic for "*"/InboundMarshaler/OutboundMarshaler. +// exactly match in the registry. +// Otherwise, it follows the above logic for "*"/InboundMarshaler/OutboundMarshaler. func MarshalerForRequest(mux *ServeMux, r *http.Request) (inbound Marshaler, outbound Marshaler) { - inbound = nil outbound = nil - headerVals := r.Header[contentTypeHeader] for _, val := range headerVals { @@ -41,7 +43,7 @@ func MarshalerForRequest(mux *ServeMux, r *http.Request) (inbound Marshaler, out } } } else { - //Nil mimeMap, no need to bother checking for MIMEWILDCARD + //Nil mimeMap, no need to bother checking for mimeWildcard if mux.InboundMarshaler == nil { //Its nil, use our default inbound = inboundDefaultMarshaler @@ -64,7 +66,7 @@ func MarshalerForRequest(mux *ServeMux, r *http.Request) (inbound Marshaler, out } if mux.MIMERegistry != nil && mux.MIMERegistry.mimeMap != nil { - if m, ok := mux.MIMERegistry.mimeMap[MIMEWILDCARD]; ok { + if m, ok := mux.MIMERegistry.mimeMap[mimeWildcard]; ok { if inbound == nil && m.inbound != nil { inbound = m.inbound } @@ -74,7 +76,7 @@ func MarshalerForRequest(mux *ServeMux, r *http.Request) (inbound Marshaler, out } } - //Haven't gotten anywhere with any of the headers or MIMEWILDCARD + //Haven't gotten anywhere with any of the headers or mimeWildcard //Try to use the mux, otherwise use our default if inbound == nil { if mux.InboundMarshaler == nil { @@ -98,6 +100,7 @@ func MarshalerForRequest(mux *ServeMux, r *http.Request) (inbound Marshaler, out } +// MarshalerMIMERegistry keeps a mapping from MIME types to mimeMarshalers. type MarshalerMIMERegistry struct { mimeMap map[string]*mimeMarshaler } @@ -107,10 +110,10 @@ type mimeMarshaler struct { outbound Marshaler } -// Add an inbound and outbund marshaler for a case-sensitive MIME type string ("*" to match any MIME type). +// AddMarshaler adds an inbound and outbund marshaler for a case-sensitive MIME type string ("*" to match any MIME type). // Inbound is the marshaler that is used when marshaling inbound requests from the client. // Outbound is the marshaler that is used when marshaling outbound responses to the client. -func (m *MarshalerMIMERegistry) AddMarshaler(mime string, inbound Marshaler, outbound Marshaler) { +func (m *MarshalerMIMERegistry) AddMarshaler(mime string, inbound, outbound Marshaler) { if len(mime) == 0 { panic("Mime can't be an empty string") @@ -123,7 +126,7 @@ func (m *MarshalerMIMERegistry) AddMarshaler(mime string, inbound Marshaler, out } -// Add an inbound marshaler for a case-sensitive MIME type string ("*" to match any MIME type). +// AddInboundMarshaler adds an inbound marshaler for a case-sensitive MIME type string ("*" to match any MIME type). // Inbound is the marshaler that is used when marshaling inbound requests from the client. func (m *MarshalerMIMERegistry) AddInboundMarshaler(mime string, inbound Marshaler) { @@ -143,7 +146,7 @@ func (m *MarshalerMIMERegistry) AddInboundMarshaler(mime string, inbound Marshal } -// Add an outbund marshaler for a case-sensitive MIME type string ("*" to match any MIME type). +// AddOutboundMarshaler adds an outbund marshaler for a case-sensitive MIME type string ("*" to match any MIME type). // Outbound is the marshaler that is used when marshaling outbound responses to the client. func (m *MarshalerMIMERegistry) AddOutboundMarshaler(mime string, outbound Marshaler) { mime = http.CanonicalHeaderKey(mime) @@ -163,8 +166,9 @@ func (m *MarshalerMIMERegistry) AddOutboundMarshaler(mime string, outbound Marsh } -// Create a new MIME marshaler registry. Allows for a mapping of case-sensitive -// Content-Type MIME type string to runtime.Marshaler interfaces. +// NewMarshalerMIMERegistry returns a new registry of marshalers. +// It allows for a mapping of case-sensitive Content-Type MIME type string to runtime.Marshaler interfaces. +// // For example, you could allow the client to specify the use of the runtime.JSONPb marshaler // with a "applicaton/jsonpb" Content-Type and the use of the runtime.JSONBuiltin marshaler // with a "application/json" Content-Type. @@ -176,44 +180,65 @@ func NewMarshalerMIMERegistry() *MarshalerMIMERegistry { } } +// Marshaler defines a conversion between byte sequence and gRPC payloads / fields. type Marshaler interface { + // Marshal marshals "v" into byte sequence. Marshal(v interface{}) ([]byte, error) + // Unmarshal unmarshals "data" into "v". + // "v" must be a pointer value. Unmarshal(data []byte, v interface{}) error + // NewDecoder returns a Decoder which reads byte sequence from "r". NewDecoder(r io.Reader) Decoder + // NewEncoder returns an Encoder which writes bytes sequence into "w". NewEncoder(w io.Writer) Encoder + // ContentType returns the Content-Type which this marshaler is responsible for. ContentType() string } +// Decoder decodes a byte sequence type Decoder interface { Decode(v interface{}) error } +// Encoder encodes gRPC payloads / fields into byte sequence. type Encoder interface { Encode(v interface{}) error } +// JSONBuiltin is a Marshaler which marshals/unmarshals into/from JSON +// with the standard "encoding/json" package of Golang. +// Although it is generally faster for simple proto messages than JSONPb, +// it does not support advanced features of protobuf, e.g. map, oneof, .... type JSONBuiltin struct{} +// ContentType always Returns "application/json". func (*JSONBuiltin) ContentType() string { return "application/json" } +// Marshal marshals "v" into JSON func (j *JSONBuiltin) Marshal(v interface{}) ([]byte, error) { return json.Marshal(v) } +// Unmarshal unmarshals JSON data into "v". func (j *JSONBuiltin) Unmarshal(data []byte, v interface{}) error { return json.Unmarshal(data, v) } +// NewDecoder returns a Decoder which reads JSON stream from "r". func (j *JSONBuiltin) NewDecoder(r io.Reader) Decoder { return json.NewDecoder(r) } +// NewEncoder returns an Encoder which writes JSON stream into "w". func (j *JSONBuiltin) NewEncoder(w io.Writer) Encoder { return json.NewEncoder(w) } +// JSONPb is a Marshaler which marshals/unmarshals into/from JSON +// with the "github.com/golang/protobuf/jsonpb". +// It supports fully functionality of protobuf unlike JSONBuiltin. type JSONPb struct { // Whether to render enum values as integers, as opposed to string values. EnumsAsInts bool @@ -231,10 +256,14 @@ type JSONPb struct { OrigName bool } +// ContentType always returns "application/json". func (*JSONPb) ContentType() string { return "application/json" } +// Marshal marshals "v" into JSON +// Currently it can marshal only proto.Message. +// TODO(yugui) Support fields of primitive types in a message. func (j *JSONPb) Marshal(v interface{}) ([]byte, error) { m := &jsonpb.Marshaler{ EnumsAsInts: j.EnumsAsInts, @@ -242,31 +271,37 @@ func (j *JSONPb) Marshal(v interface{}) ([]byte, error) { Indent: j.Indent, OrigName: j.OrigName, } - if p, ok := v.(proto.Message); ok { - var buf bytes.Buffer - if err := m.Marshal(&buf, p); err != nil { - return nil, err - } - return buf.Bytes(), nil - } else { - return nil, errors.New("Interface is not proto.Message") + p, ok := v.(proto.Message) + if !ok { + return nil, errors.New("interface is not proto.Message") } + var buf bytes.Buffer + if err := m.Marshal(&buf, p); err != nil { + return nil, err + } + return buf.Bytes(), nil + } +// Unmarshal unmarshals JSON "data" into "v" +// Currently it can marshal only proto.Message. +// TODO(yugui) Support fields of primitive types in a message. func (j *JSONPb) Unmarshal(data []byte, v interface{}) error { r := bytes.NewReader(data) - if p, ok := v.(proto.Message); ok { - return jsonpb.Unmarshal(r, p) - } else { - return errors.New("Interface is not proto.Message") + p, ok := v.(proto.Message) + if !ok { + return errors.New("interface is not proto.Message") } + return jsonpb.Unmarshal(r, p) } +// NewDecoder returns a Decoder which reads JSON stream from "r". func (j *JSONPb) NewDecoder(r io.Reader) Decoder { - return &JSONPbDecoder{decoder: json.NewDecoder(r)} + return &jsonPbDecoder{decoder: json.NewDecoder(r)} } +// NewEncoder returns an Encoder which writes JSON stream into "w". func (j *JSONPb) NewEncoder(w io.Writer) Encoder { m := &jsonpb.Marshaler{ EnumsAsInts: j.EnumsAsInts, @@ -275,33 +310,34 @@ func (j *JSONPb) NewEncoder(w io.Writer) Encoder { OrigName: j.OrigName, } - return &JSONPbEncoder{ + return &jsonPbEncoder{ marshal: m, writer: w, } } -type JSONPbDecoder struct { +type jsonPbDecoder struct { decoder *json.Decoder } -func (j *JSONPbDecoder) Decode(v interface{}) error { - if p, ok := v.(proto.Message); ok { - return jsonpb.UnmarshalNext(j.decoder, p) - } else { - return errors.New("Interface is not proto.Message") +func (j *jsonPbDecoder) Decode(v interface{}) error { + p, ok := v.(proto.Message) + if !ok { + return errors.New("interface is not proto.Message") } + + return jsonpb.UnmarshalNext(j.decoder, p) } -type JSONPbEncoder struct { +type jsonPbEncoder struct { marshal *jsonpb.Marshaler writer io.Writer } -func (j *JSONPbEncoder) Encode(v interface{}) error { - if p, ok := v.(proto.Message); ok { - return j.marshal.Marshal(j.writer, p) - } else { - return errors.New("Interface is not proto.Message") +func (j *jsonPbEncoder) Encode(v interface{}) error { + p, ok := v.(proto.Message) + if !ok { + return errors.New("interface is not proto.Message") } + return j.marshal.Marshal(j.writer, p) } From 69311feca92df2497beee2a9d0054142e78a26ee Mon Sep 17 00:00:00 2001 From: Yuki Yugui Sonoda Date: Mon, 9 May 2016 11:34:20 +0900 Subject: [PATCH 2/4] Split marshaler implementation into smaller files --- runtime/marshal_json.go | 37 ++++++++++ runtime/marshal_jsonpb.go | 117 +++++++++++++++++++++++++++++++ runtime/marshaler.go | 143 -------------------------------------- 3 files changed, 154 insertions(+), 143 deletions(-) create mode 100644 runtime/marshal_json.go create mode 100644 runtime/marshal_jsonpb.go diff --git a/runtime/marshal_json.go b/runtime/marshal_json.go new file mode 100644 index 00000000000..0acd2ca29ef --- /dev/null +++ b/runtime/marshal_json.go @@ -0,0 +1,37 @@ +package runtime + +import ( + "encoding/json" + "io" +) + +// JSONBuiltin is a Marshaler which marshals/unmarshals into/from JSON +// with the standard "encoding/json" package of Golang. +// Although it is generally faster for simple proto messages than JSONPb, +// it does not support advanced features of protobuf, e.g. map, oneof, .... +type JSONBuiltin struct{} + +// ContentType always Returns "application/json". +func (*JSONBuiltin) ContentType() string { + return "application/json" +} + +// Marshal marshals "v" into JSON +func (j *JSONBuiltin) Marshal(v interface{}) ([]byte, error) { + return json.Marshal(v) +} + +// Unmarshal unmarshals JSON data into "v". +func (j *JSONBuiltin) Unmarshal(data []byte, v interface{}) error { + return json.Unmarshal(data, v) +} + +// NewDecoder returns a Decoder which reads JSON stream from "r". +func (j *JSONBuiltin) NewDecoder(r io.Reader) Decoder { + return json.NewDecoder(r) +} + +// NewEncoder returns an Encoder which writes JSON stream into "w". +func (j *JSONBuiltin) NewEncoder(w io.Writer) Encoder { + return json.NewEncoder(w) +} diff --git a/runtime/marshal_jsonpb.go b/runtime/marshal_jsonpb.go new file mode 100644 index 00000000000..73a86a38f7c --- /dev/null +++ b/runtime/marshal_jsonpb.go @@ -0,0 +1,117 @@ +package runtime + +import ( + "bytes" + "encoding/json" + "errors" + "io" + + "github.com/golang/protobuf/jsonpb" + "github.com/golang/protobuf/proto" +) + +// JSONPb is a Marshaler which marshals/unmarshals into/from JSON +// with the "github.com/golang/protobuf/jsonpb". +// It supports fully functionality of protobuf unlike JSONBuiltin. +type JSONPb struct { + // Whether to render enum values as integers, as opposed to string values. + EnumsAsInts bool + + // Whether to render fields with zero values. + EmitDefaults bool + + // A string to indent each level by. The presence of this field will + // also cause a space to appear between the field separator and + // value, and for newlines to be appear between fields and array + // elements. + Indent string + + // Whether to use the original (.proto) name for fields. + OrigName bool +} + +// ContentType always returns "application/json". +func (*JSONPb) ContentType() string { + return "application/json" +} + +// Marshal marshals "v" into JSON +// Currently it can marshal only proto.Message. +// TODO(yugui) Support fields of primitive types in a message. +func (j *JSONPb) Marshal(v interface{}) ([]byte, error) { + m := &jsonpb.Marshaler{ + EnumsAsInts: j.EnumsAsInts, + EmitDefaults: j.EmitDefaults, + Indent: j.Indent, + OrigName: j.OrigName, + } + p, ok := v.(proto.Message) + if !ok { + return nil, errors.New("interface is not proto.Message") + } + + var buf bytes.Buffer + if err := m.Marshal(&buf, p); err != nil { + return nil, err + } + return buf.Bytes(), nil + +} + +// Unmarshal unmarshals JSON "data" into "v" +// Currently it can marshal only proto.Message. +// TODO(yugui) Support fields of primitive types in a message. +func (j *JSONPb) Unmarshal(data []byte, v interface{}) error { + r := bytes.NewReader(data) + p, ok := v.(proto.Message) + if !ok { + return errors.New("interface is not proto.Message") + } + return jsonpb.Unmarshal(r, p) +} + +// NewDecoder returns a Decoder which reads JSON stream from "r". +func (j *JSONPb) NewDecoder(r io.Reader) Decoder { + return &jsonPbDecoder{decoder: json.NewDecoder(r)} +} + +// NewEncoder returns an Encoder which writes JSON stream into "w". +func (j *JSONPb) NewEncoder(w io.Writer) Encoder { + m := &jsonpb.Marshaler{ + EnumsAsInts: j.EnumsAsInts, + EmitDefaults: j.EmitDefaults, + Indent: j.Indent, + OrigName: j.OrigName, + } + + return &jsonPbEncoder{ + marshal: m, + writer: w, + } +} + +type jsonPbDecoder struct { + decoder *json.Decoder +} + +func (j *jsonPbDecoder) Decode(v interface{}) error { + p, ok := v.(proto.Message) + if !ok { + return errors.New("interface is not proto.Message") + } + + return jsonpb.UnmarshalNext(j.decoder, p) +} + +type jsonPbEncoder struct { + marshal *jsonpb.Marshaler + writer io.Writer +} + +func (j *jsonPbEncoder) Encode(v interface{}) error { + p, ok := v.(proto.Message) + if !ok { + return errors.New("interface is not proto.Message") + } + return j.marshal.Marshal(j.writer, p) +} diff --git a/runtime/marshaler.go b/runtime/marshaler.go index b250d33ec03..aa202fb397a 100644 --- a/runtime/marshaler.go +++ b/runtime/marshaler.go @@ -1,14 +1,8 @@ package runtime import ( - "bytes" - "encoding/json" - "errors" "io" "net/http" - - "github.com/golang/protobuf/jsonpb" - "github.com/golang/protobuf/proto" ) const mimeWildcard = "*" @@ -204,140 +198,3 @@ type Decoder interface { type Encoder interface { Encode(v interface{}) error } - -// JSONBuiltin is a Marshaler which marshals/unmarshals into/from JSON -// with the standard "encoding/json" package of Golang. -// Although it is generally faster for simple proto messages than JSONPb, -// it does not support advanced features of protobuf, e.g. map, oneof, .... -type JSONBuiltin struct{} - -// ContentType always Returns "application/json". -func (*JSONBuiltin) ContentType() string { - return "application/json" -} - -// Marshal marshals "v" into JSON -func (j *JSONBuiltin) Marshal(v interface{}) ([]byte, error) { - return json.Marshal(v) -} - -// Unmarshal unmarshals JSON data into "v". -func (j *JSONBuiltin) Unmarshal(data []byte, v interface{}) error { - return json.Unmarshal(data, v) -} - -// NewDecoder returns a Decoder which reads JSON stream from "r". -func (j *JSONBuiltin) NewDecoder(r io.Reader) Decoder { - return json.NewDecoder(r) -} - -// NewEncoder returns an Encoder which writes JSON stream into "w". -func (j *JSONBuiltin) NewEncoder(w io.Writer) Encoder { - return json.NewEncoder(w) -} - -// JSONPb is a Marshaler which marshals/unmarshals into/from JSON -// with the "github.com/golang/protobuf/jsonpb". -// It supports fully functionality of protobuf unlike JSONBuiltin. -type JSONPb struct { - // Whether to render enum values as integers, as opposed to string values. - EnumsAsInts bool - - // Whether to render fields with zero values. - EmitDefaults bool - - // A string to indent each level by. The presence of this field will - // also cause a space to appear between the field separator and - // value, and for newlines to be appear between fields and array - // elements. - Indent string - - // Whether to use the original (.proto) name for fields. - OrigName bool -} - -// ContentType always returns "application/json". -func (*JSONPb) ContentType() string { - return "application/json" -} - -// Marshal marshals "v" into JSON -// Currently it can marshal only proto.Message. -// TODO(yugui) Support fields of primitive types in a message. -func (j *JSONPb) Marshal(v interface{}) ([]byte, error) { - m := &jsonpb.Marshaler{ - EnumsAsInts: j.EnumsAsInts, - EmitDefaults: j.EmitDefaults, - Indent: j.Indent, - OrigName: j.OrigName, - } - p, ok := v.(proto.Message) - if !ok { - return nil, errors.New("interface is not proto.Message") - } - - var buf bytes.Buffer - if err := m.Marshal(&buf, p); err != nil { - return nil, err - } - return buf.Bytes(), nil - -} - -// Unmarshal unmarshals JSON "data" into "v" -// Currently it can marshal only proto.Message. -// TODO(yugui) Support fields of primitive types in a message. -func (j *JSONPb) Unmarshal(data []byte, v interface{}) error { - r := bytes.NewReader(data) - p, ok := v.(proto.Message) - if !ok { - return errors.New("interface is not proto.Message") - } - return jsonpb.Unmarshal(r, p) -} - -// NewDecoder returns a Decoder which reads JSON stream from "r". -func (j *JSONPb) NewDecoder(r io.Reader) Decoder { - return &jsonPbDecoder{decoder: json.NewDecoder(r)} -} - -// NewEncoder returns an Encoder which writes JSON stream into "w". -func (j *JSONPb) NewEncoder(w io.Writer) Encoder { - m := &jsonpb.Marshaler{ - EnumsAsInts: j.EnumsAsInts, - EmitDefaults: j.EmitDefaults, - Indent: j.Indent, - OrigName: j.OrigName, - } - - return &jsonPbEncoder{ - marshal: m, - writer: w, - } -} - -type jsonPbDecoder struct { - decoder *json.Decoder -} - -func (j *jsonPbDecoder) Decode(v interface{}) error { - p, ok := v.(proto.Message) - if !ok { - return errors.New("interface is not proto.Message") - } - - return jsonpb.UnmarshalNext(j.decoder, p) -} - -type jsonPbEncoder struct { - marshal *jsonpb.Marshaler - writer io.Writer -} - -func (j *jsonPbEncoder) Encode(v interface{}) error { - p, ok := v.(proto.Message) - if !ok { - return errors.New("interface is not proto.Message") - } - return j.marshal.Marshal(j.writer, p) -} From 8c662237a925a29fa34ce094522d2432570fe757 Mon Sep 17 00:00:00 2001 From: Yuki Yugui Sonoda Date: Mon, 9 May 2016 12:44:00 +0900 Subject: [PATCH 3/4] Add map and oneof into the example --- examples/examplepb/a_bit_of_everything.pb.go | 243 ++++++++++++++----- examples/examplepb/a_bit_of_everything.proto | 6 + 2 files changed, 189 insertions(+), 60 deletions(-) diff --git a/examples/examplepb/a_bit_of_everything.pb.go b/examples/examplepb/a_bit_of_everything.pb.go index 21b8e96c92c..4ba8752c92e 100644 --- a/examples/examplepb/a_bit_of_everything.pb.go +++ b/examples/examplepb/a_bit_of_everything.pb.go @@ -85,6 +85,11 @@ type ABitOfEverything struct { Sint32Value int32 `protobuf:"zigzag32,17,opt,name=sint32_value,json=sint32Value" json:"sint32_value,omitempty"` Sint64Value int64 `protobuf:"zigzag64,18,opt,name=sint64_value,json=sint64Value" json:"sint64_value,omitempty"` RepeatedStringValue []string `protobuf:"bytes,19,rep,name=repeated_string_value,json=repeatedStringValue" json:"repeated_string_value,omitempty"` + // Types that are valid to be assigned to OneofValue: + // *ABitOfEverything_OneofEmpty + // *ABitOfEverything_OneofString + OneofValue isABitOfEverything_OneofValue `protobuf_oneof:"oneof_value"` + MapValue map[string]NumericEnum `protobuf:"bytes,22,rep,name=map_value,json=mapValue" json:"map_value,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"varint,2,opt,name=value,enum=gengo.grpc.gateway.examples.examplepb.NumericEnum"` } func (m *ABitOfEverything) Reset() { *m = ABitOfEverything{} } @@ -92,6 +97,27 @@ func (m *ABitOfEverything) String() string { return proto.CompactText func (*ABitOfEverything) ProtoMessage() {} func (*ABitOfEverything) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{0} } +type isABitOfEverything_OneofValue interface { + isABitOfEverything_OneofValue() +} + +type ABitOfEverything_OneofEmpty struct { + OneofEmpty *EmptyMessage `protobuf:"bytes,20,opt,name=oneof_empty,json=oneofEmpty,oneof"` +} +type ABitOfEverything_OneofString struct { + OneofString string `protobuf:"bytes,21,opt,name=oneof_string,json=oneofString,oneof"` +} + +func (*ABitOfEverything_OneofEmpty) isABitOfEverything_OneofValue() {} +func (*ABitOfEverything_OneofString) isABitOfEverything_OneofValue() {} + +func (m *ABitOfEverything) GetOneofValue() isABitOfEverything_OneofValue { + if m != nil { + return m.OneofValue + } + return nil +} + func (m *ABitOfEverything) GetNested() []*ABitOfEverything_Nested { if m != nil { return m.Nested @@ -99,6 +125,97 @@ func (m *ABitOfEverything) GetNested() []*ABitOfEverything_Nested { return nil } +func (m *ABitOfEverything) GetOneofEmpty() *EmptyMessage { + if x, ok := m.GetOneofValue().(*ABitOfEverything_OneofEmpty); ok { + return x.OneofEmpty + } + return nil +} + +func (m *ABitOfEverything) GetOneofString() string { + if x, ok := m.GetOneofValue().(*ABitOfEverything_OneofString); ok { + return x.OneofString + } + return "" +} + +func (m *ABitOfEverything) GetMapValue() map[string]NumericEnum { + if m != nil { + return m.MapValue + } + return nil +} + +// XXX_OneofFuncs is for the internal use of the proto package. +func (*ABitOfEverything) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { + return _ABitOfEverything_OneofMarshaler, _ABitOfEverything_OneofUnmarshaler, _ABitOfEverything_OneofSizer, []interface{}{ + (*ABitOfEverything_OneofEmpty)(nil), + (*ABitOfEverything_OneofString)(nil), + } +} + +func _ABitOfEverything_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { + m := msg.(*ABitOfEverything) + // oneof_value + switch x := m.OneofValue.(type) { + case *ABitOfEverything_OneofEmpty: + b.EncodeVarint(20<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.OneofEmpty); err != nil { + return err + } + case *ABitOfEverything_OneofString: + b.EncodeVarint(21<<3 | proto.WireBytes) + b.EncodeStringBytes(x.OneofString) + case nil: + default: + return fmt.Errorf("ABitOfEverything.OneofValue has unexpected type %T", x) + } + return nil +} + +func _ABitOfEverything_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { + m := msg.(*ABitOfEverything) + switch tag { + case 20: // oneof_value.oneof_empty + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(EmptyMessage) + err := b.DecodeMessage(msg) + m.OneofValue = &ABitOfEverything_OneofEmpty{msg} + return true, err + case 21: // oneof_value.oneof_string + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeStringBytes() + m.OneofValue = &ABitOfEverything_OneofString{x} + return true, err + default: + return false, nil + } +} + +func _ABitOfEverything_OneofSizer(msg proto.Message) (n int) { + m := msg.(*ABitOfEverything) + // oneof_value + switch x := m.OneofValue.(type) { + case *ABitOfEverything_OneofEmpty: + s := proto.Size(x.OneofEmpty) + n += proto.SizeVarint(20<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *ABitOfEverything_OneofString: + n += proto.SizeVarint(21<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(len(x.OneofString))) + n += len(x.OneofString) + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + return n +} + type ABitOfEverything_Nested struct { Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` Amount uint32 `protobuf:"varint,2,opt,name=amount" json:"amount,omitempty"` @@ -556,64 +673,70 @@ var _ABitOfEverythingService_serviceDesc = grpc.ServiceDesc{ } var fileDescriptor1 = []byte{ - // 932 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xc4, 0x56, 0xdd, 0x8e, 0xdb, 0x44, - 0x14, 0xc6, 0x49, 0xd6, 0x49, 0xc6, 0x9b, 0x6c, 0x3a, 0x15, 0xb0, 0x04, 0xd0, 0x6e, 0x4d, 0x0b, - 0x21, 0x54, 0x76, 0xeb, 0x20, 0x90, 0x2a, 0x81, 0xd4, 0xd0, 0x80, 0x90, 0x96, 0x5d, 0xe1, 0xa5, - 0x45, 0x8a, 0x84, 0x22, 0x27, 0x9e, 0xb8, 0xd6, 0x3a, 0x1e, 0xcb, 0x3f, 0xa1, 0x51, 0x14, 0x2e, - 0x7a, 0x85, 0xc4, 0x05, 0x12, 0x3c, 0x00, 0x12, 0x77, 0x20, 0xc1, 0x8b, 0xf4, 0x92, 0x57, 0xe0, - 0x41, 0x38, 0x1e, 0xff, 0x74, 0x9c, 0x22, 0x12, 0x52, 0x69, 0x7b, 0x97, 0x99, 0xf3, 0xcd, 0x77, - 0xbe, 0x73, 0xce, 0x37, 0xe3, 0xa0, 0x9b, 0xe4, 0x91, 0x31, 0xf3, 0x1c, 0x12, 0xa8, 0xe9, 0x0f, - 0x6f, 0xac, 0x1a, 0xa3, 0xb1, 0x1d, 0x8e, 0xe8, 0x74, 0x44, 0xe6, 0xc4, 0x5f, 0x84, 0x0f, 0x6d, - 0xd7, 0x52, 0x3c, 0x9f, 0x86, 0x14, 0xdf, 0xb0, 0x88, 0x6b, 0x51, 0xc5, 0xf2, 0xbd, 0x89, 0x62, - 0x19, 0x21, 0xf9, 0xd6, 0x58, 0x28, 0x19, 0x81, 0x92, 0x13, 0xb4, 0xdf, 0xb0, 0x28, 0xb5, 0x1c, - 0xa2, 0x1a, 0x9e, 0xad, 0x1a, 0xae, 0x4b, 0x43, 0x23, 0xb4, 0xa9, 0x1b, 0x24, 0x24, 0xed, 0x76, - 0x9e, 0x32, 0x88, 0xc6, 0xea, 0x8c, 0x04, 0x81, 0x61, 0x91, 0x34, 0xf6, 0x3a, 0x1f, 0xd3, 0x8a, - 0x41, 0xf9, 0xd7, 0x2a, 0x6a, 0xdd, 0xed, 0xdb, 0xe1, 0xd9, 0x74, 0x90, 0x0b, 0xc3, 0x18, 0x55, - 0xa2, 0xc8, 0x36, 0x0f, 0x85, 0x63, 0xa1, 0x53, 0xd7, 0xd9, 0x6f, 0xfc, 0x00, 0x89, 0x2e, 0x09, - 0x42, 0x62, 0x1e, 0x96, 0x8e, 0xcb, 0x1d, 0x49, 0xfb, 0x58, 0xd9, 0x4a, 0xb7, 0xb2, 0x4e, 0xae, - 0x9c, 0x32, 0x16, 0x3d, 0x65, 0xc3, 0x47, 0x48, 0x9a, 0x3a, 0xd4, 0x08, 0x47, 0x73, 0xc3, 0x89, - 0xc8, 0x61, 0x19, 0x52, 0x96, 0x74, 0xc4, 0xb6, 0x1e, 0xc4, 0x3b, 0xf8, 0x1a, 0xda, 0x37, 0x69, - 0x34, 0x76, 0x48, 0x8a, 0xa8, 0x00, 0x42, 0xd0, 0xa5, 0x64, 0x2f, 0x81, 0x00, 0x87, 0xed, 0x86, - 0x1f, 0xbc, 0x9f, 0x22, 0xf6, 0x00, 0x51, 0xd6, 0x11, 0xdb, 0xca, 0x39, 0x22, 0x1e, 0x21, 0x02, - 0xa2, 0xa2, 0x4b, 0x11, 0x07, 0x49, 0x38, 0x7a, 0x5a, 0x8a, 0xa8, 0x02, 0x62, 0x8f, 0x71, 0xf4, - 0xb4, 0x04, 0xf0, 0x16, 0x6a, 0x4c, 0xed, 0x47, 0xc4, 0xcc, 0x49, 0x6a, 0x00, 0x11, 0xf5, 0xfd, - 0x74, 0xb3, 0x08, 0xca, 0x79, 0xea, 0x00, 0xaa, 0xa6, 0xa0, 0x8c, 0xe9, 0x4d, 0x84, 0xc6, 0x94, - 0x3a, 0x29, 0x02, 0x01, 0xa2, 0xa6, 0xd7, 0xe3, 0x9d, 0x5c, 0x6c, 0x10, 0xfa, 0xd0, 0xaa, 0x14, - 0x20, 0xb1, 0x29, 0x48, 0xc9, 0x5e, 0xa1, 0x9e, 0x3c, 0x4b, 0x03, 0x20, 0x8d, 0xa4, 0x9e, 0x2c, - 0xc9, 0x97, 0x08, 0x11, 0x37, 0x9a, 0xa5, 0x80, 0x26, 0x00, 0x9a, 0x9a, 0xb6, 0xe5, 0xcc, 0x4e, - 0xa3, 0x19, 0xf1, 0xed, 0xc9, 0x00, 0xce, 0xeb, 0xf5, 0x98, 0x25, 0xa1, 0xbc, 0x81, 0x9a, 0x41, - 0xb1, 0xba, 0x03, 0xa0, 0x3d, 0xd0, 0x1b, 0x41, 0xa1, 0xbc, 0x1c, 0x96, 0x77, 0xaa, 0x05, 0xb0, - 0x56, 0x06, 0xe3, 0x66, 0x12, 0xf0, 0x35, 0x5c, 0x01, 0xd0, 0x15, 0x28, 0x93, 0xab, 0x21, 0x85, - 0xe4, 0x3c, 0x18, 0x20, 0x38, 0x81, 0x64, 0x2c, 0x1a, 0x7a, 0xd9, 0x27, 0x1e, 0x81, 0x5a, 0xcc, - 0x51, 0xa1, 0x6b, 0x57, 0xc1, 0xa5, 0x75, 0xfd, 0x6a, 0x16, 0x3c, 0x7f, 0xda, 0xbd, 0xf6, 0x9f, - 0x02, 0x12, 0x13, 0x17, 0xc6, 0x4e, 0x77, 0x8d, 0x19, 0xc9, 0x9c, 0x1e, 0xff, 0xc6, 0xaf, 0x20, - 0xd1, 0x98, 0xd1, 0xc8, 0x0d, 0xc1, 0xe9, 0x71, 0x5b, 0xd3, 0x15, 0xfe, 0x1a, 0x95, 0xe8, 0x05, - 0x33, 0x68, 0x53, 0xfb, 0xec, 0xf9, 0xdc, 0xaf, 0xdc, 0x23, 0xc4, 0x63, 0xed, 0x05, 0x4a, 0xf9, - 0x08, 0xd5, 0xb2, 0x35, 0xae, 0xa3, 0xbd, 0x4f, 0xef, 0x9e, 0x9c, 0x0f, 0x5a, 0x2f, 0xe1, 0x1a, - 0xaa, 0x7c, 0xa5, 0xdf, 0x1f, 0xb4, 0x04, 0xb9, 0x89, 0xf6, 0x07, 0x33, 0x2f, 0x5c, 0x7c, 0x91, - 0x5c, 0xdd, 0xee, 0x31, 0x92, 0xb8, 0x11, 0xc5, 0xc0, 0xe1, 0x40, 0x3f, 0x83, 0x23, 0x55, 0x54, - 0x3e, 0x3b, 0x85, 0x13, 0xda, 0x93, 0x06, 0x7a, 0x75, 0x3d, 0xf7, 0x39, 0xf1, 0xe7, 0xf6, 0x84, - 0xe0, 0x1f, 0xcb, 0x48, 0xfc, 0xc4, 0x8f, 0xbb, 0x82, 0x3f, 0xdc, 0xb1, 0x8c, 0xf6, 0xae, 0x07, - 0xe5, 0x9f, 0x4a, 0x8f, 0xff, 0xfa, 0xfb, 0xe7, 0xd2, 0x0f, 0x25, 0xf9, 0xfb, 0x92, 0x3a, 0xbf, - 0x9d, 0xbd, 0x90, 0xff, 0xf6, 0x3e, 0xaa, 0x4b, 0xee, 0x61, 0x58, 0xa9, 0x4b, 0xfe, 0x15, 0x80, - 0x25, 0x67, 0x8c, 0x95, 0x1a, 0x10, 0xcf, 0xf0, 0x8d, 0x90, 0xfa, 0xea, 0x32, 0x2a, 0x04, 0x96, - 0x9c, 0xc5, 0x60, 0x55, 0xf0, 0x65, 0xb6, 0xe6, 0xe2, 0x4f, 0xef, 0x25, 0x2c, 0x78, 0x3f, 0x7d, - 0x04, 0x0b, 0xcf, 0x27, 0x80, 0x57, 0xbb, 0xab, 0x24, 0x09, 0x77, 0x2c, 0x58, 0xe7, 0x09, 0xd6, - 0x13, 0x05, 0x6b, 0x07, 0x78, 0x91, 0xf8, 0x77, 0x01, 0xa1, 0x64, 0x22, 0x7d, 0x6a, 0x2e, 0x5e, - 0xc0, 0x54, 0xba, 0x6c, 0x28, 0xd7, 0xe5, 0xa3, 0x0d, 0x23, 0xb9, 0x23, 0x74, 0xf1, 0x1f, 0x20, - 0xb6, 0x1f, 0x39, 0x17, 0xcf, 0x6b, 0xa1, 0xde, 0x96, 0x07, 0x79, 0xe7, 0xcb, 0x2a, 0x13, 0xfa, - 0xae, 0x7c, 0x7d, 0x93, 0x77, 0xc6, 0xa0, 0x10, 0xd4, 0x76, 0x04, 0xfc, 0x18, 0x6e, 0xfb, 0x09, - 0xa5, 0x17, 0x91, 0x87, 0x0f, 0x94, 0xf8, 0x0b, 0xa8, 0x7c, 0x6e, 0xa6, 0x74, 0xbb, 0x37, 0x4c, - 0x61, 0x3a, 0x3a, 0xf8, 0xed, 0x8d, 0x1e, 0x8e, 0x3f, 0x9e, 0x2b, 0xfc, 0x8b, 0x80, 0x2a, 0x27, - 0x76, 0x10, 0xe2, 0x5d, 0xaa, 0xde, 0x5d, 0xe6, 0x3b, 0x4c, 0xe6, 0x35, 0xbc, 0x69, 0xae, 0xb7, - 0x04, 0xfc, 0x1b, 0xb4, 0xe9, 0xbe, 0x67, 0x5e, 0xfe, 0x48, 0x6f, 0x33, 0x8d, 0xef, 0xb5, 0xb7, - 0x6c, 0x65, 0x6c, 0xc1, 0xef, 0x90, 0x78, 0x8f, 0x38, 0x04, 0xa4, 0x3e, 0x33, 0xd1, 0x9d, 0x24, - 0xa4, 0xd3, 0xec, 0x6e, 0x3b, 0xcd, 0x27, 0x30, 0xcd, 0xc1, 0xe4, 0x21, 0xc5, 0xca, 0x7f, 0x66, - 0x03, 0x69, 0x4a, 0xf2, 0xdd, 0xc9, 0xd4, 0xfd, 0x4f, 0xbc, 0x3c, 0x61, 0xc2, 0xbe, 0xc1, 0x37, - 0x37, 0x09, 0x23, 0xa0, 0x46, 0x5d, 0x26, 0xcf, 0xc9, 0xf0, 0x35, 0xb9, 0xa5, 0xce, 0xb5, 0x1c, - 0x1f, 0xc7, 0xee, 0xec, 0xb1, 0xd8, 0x10, 0xe3, 0x67, 0x42, 0xb1, 0x37, 0x6b, 0xf1, 0x85, 0xbe, - 0x94, 0x8a, 0xb6, 0xbe, 0xc0, 0x4c, 0x75, 0x7c, 0x81, 0x6f, 0x09, 0x7d, 0x69, 0x58, 0xcf, 0x27, - 0x37, 0x16, 0xd9, 0x1f, 0xd7, 0xde, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x17, 0x44, 0xcc, 0x34, - 0x66, 0x0b, 0x00, 0x00, + // 1033 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xc4, 0x57, 0xdd, 0x6e, 0x1b, 0x45, + 0x18, 0xed, 0xda, 0x89, 0x63, 0x7f, 0x1b, 0x3b, 0xee, 0x94, 0x16, 0x63, 0x40, 0x49, 0x97, 0x16, + 0x82, 0xa9, 0x76, 0xdb, 0x0d, 0x02, 0x14, 0x09, 0xa4, 0x9a, 0x1a, 0x8a, 0x94, 0x26, 0x62, 0x43, + 0x83, 0x14, 0x09, 0x59, 0x6b, 0x7b, 0xe2, 0xae, 0x62, 0xef, 0xac, 0xf6, 0xc7, 0xd4, 0xb2, 0xc2, + 0x45, 0xb9, 0x41, 0xe2, 0x02, 0x09, 0x1e, 0x80, 0x6b, 0x90, 0xe0, 0x45, 0x7a, 0xc9, 0x2b, 0xf0, + 0x20, 0x7c, 0x33, 0xb3, 0xbb, 0xac, 0x5d, 0x84, 0xcd, 0x56, 0x2a, 0x77, 0x3b, 0x33, 0x67, 0xce, + 0x9c, 0xef, 0xe7, 0xcc, 0xd8, 0x70, 0x8b, 0x3e, 0xb6, 0xc7, 0xde, 0x88, 0x06, 0x46, 0xfc, 0xe1, + 0xf5, 0x0c, 0xbb, 0xdb, 0x73, 0xc2, 0x2e, 0x3b, 0xeb, 0xd2, 0x09, 0xf5, 0xa7, 0xe1, 0x23, 0xc7, + 0x1d, 0xea, 0x9e, 0xcf, 0x42, 0x46, 0x6e, 0x0e, 0xa9, 0x3b, 0x64, 0xfa, 0xd0, 0xf7, 0xfa, 0xfa, + 0xd0, 0x0e, 0xe9, 0xd7, 0xf6, 0x54, 0x4f, 0x08, 0xf4, 0x94, 0xa0, 0xf9, 0xda, 0x90, 0xb1, 0xe1, + 0x88, 0x1a, 0xb6, 0xe7, 0x18, 0xb6, 0xeb, 0xb2, 0xd0, 0x0e, 0x1d, 0xe6, 0x06, 0x92, 0xa4, 0xd9, + 0x4c, 0x8f, 0x0c, 0xa2, 0x9e, 0x31, 0xa6, 0x41, 0x60, 0x0f, 0x69, 0xbc, 0xf6, 0x6a, 0x76, 0xcd, + 0x9c, 0x5f, 0xd4, 0xbe, 0x05, 0xa8, 0xdf, 0x6d, 0x3b, 0xe1, 0xd1, 0x59, 0x27, 0x15, 0x46, 0x08, + 0xac, 0x45, 0x91, 0x33, 0x68, 0x28, 0x3b, 0xca, 0x6e, 0xc5, 0x12, 0xdf, 0xe4, 0x04, 0x4a, 0x2e, + 0x0d, 0x42, 0x3a, 0x68, 0x14, 0x76, 0x8a, 0xbb, 0xaa, 0xf9, 0x91, 0xbe, 0x92, 0x6e, 0x7d, 0x91, + 0x5c, 0x3f, 0x14, 0x2c, 0x56, 0xcc, 0x46, 0xb6, 0x41, 0x3d, 0x1b, 0x31, 0x3b, 0xec, 0x4e, 0xec, + 0x51, 0x44, 0x1b, 0x45, 0x3c, 0xb2, 0x60, 0x81, 0x98, 0x3a, 0xe1, 0x33, 0xe4, 0x3a, 0x6c, 0x0e, + 0x58, 0xd4, 0x1b, 0xd1, 0x18, 0xb1, 0x86, 0x08, 0xc5, 0x52, 0xe5, 0x9c, 0x84, 0x20, 0x87, 0xe3, + 0x86, 0xef, 0xbd, 0x1b, 0x23, 0xd6, 0x11, 0x51, 0xb4, 0x40, 0x4c, 0xa5, 0x1c, 0x51, 0x16, 0x51, + 0x42, 0xc4, 0x9a, 0xa5, 0x46, 0x19, 0x88, 0xe4, 0xd8, 0x33, 0x63, 0xc4, 0x06, 0x22, 0xd6, 0x05, + 0xc7, 0x9e, 0x29, 0x01, 0x6f, 0x40, 0xf5, 0xcc, 0x79, 0x4c, 0x07, 0x29, 0x49, 0x19, 0x21, 0x25, + 0x6b, 0x33, 0x9e, 0x9c, 0x07, 0xa5, 0x3c, 0x15, 0x04, 0x6d, 0xc4, 0xa0, 0x84, 0xe9, 0x75, 0x80, + 0x1e, 0x63, 0xa3, 0x18, 0x01, 0x88, 0x28, 0x5b, 0x15, 0x3e, 0x93, 0x8a, 0x0d, 0x42, 0x1f, 0x53, + 0x15, 0x03, 0x54, 0x51, 0x05, 0x55, 0xce, 0xcd, 0xc5, 0x93, 0x9e, 0x52, 0x45, 0x48, 0x55, 0xc6, + 0x93, 0x1c, 0xf2, 0x39, 0x00, 0x75, 0xa3, 0x71, 0x0c, 0xa8, 0x21, 0xa0, 0x66, 0x9a, 0x2b, 0xd6, + 0xec, 0x30, 0x1a, 0x53, 0xdf, 0xe9, 0x77, 0x70, 0xbf, 0x55, 0xe1, 0x2c, 0x92, 0xf2, 0x26, 0xd4, + 0x82, 0xf9, 0xe8, 0xb6, 0x90, 0x76, 0xcb, 0xaa, 0x06, 0x73, 0xe1, 0xa5, 0xb0, 0x34, 0x53, 0x75, + 0x84, 0xd5, 0x13, 0x58, 0xa6, 0x26, 0x41, 0x36, 0x86, 0xcb, 0x08, 0xba, 0x8c, 0x61, 0x66, 0x62, + 0x88, 0x21, 0x29, 0x0f, 0x41, 0x08, 0x91, 0x90, 0x84, 0xc5, 0x84, 0xab, 0x3e, 0xf5, 0x28, 0xc6, + 0x32, 0xe8, 0xce, 0x65, 0xed, 0x0a, 0x76, 0x69, 0xc5, 0xba, 0x92, 0x2c, 0x1e, 0x67, 0xb2, 0x77, + 0x02, 0x2a, 0x73, 0x29, 0xf7, 0xe2, 0xd8, 0x0b, 0xa7, 0x8d, 0x97, 0x90, 0x55, 0x35, 0xf7, 0x56, + 0xcc, 0x4d, 0x87, 0xef, 0x79, 0x20, 0x3d, 0x74, 0xff, 0x92, 0x05, 0x82, 0x49, 0x4c, 0x62, 0xf1, + 0x37, 0x25, 0xaf, 0x14, 0xd2, 0xb8, 0xca, 0x0b, 0x87, 0x18, 0x79, 0x9a, 0x54, 0x40, 0x7a, 0x50, + 0x19, 0xdb, 0x5e, 0x2c, 0xf2, 0x9a, 0xb0, 0x52, 0x27, 0xaf, 0x95, 0x1e, 0xd8, 0x9e, 0x88, 0xa8, + 0xe3, 0x86, 0xfe, 0xd4, 0x2a, 0x8f, 0xe3, 0x61, 0xf3, 0x77, 0x05, 0x4a, 0xd2, 0x66, 0xdc, 0xca, + 0xae, 0x3d, 0xa6, 0x89, 0x95, 0xf9, 0x37, 0xb9, 0x06, 0x25, 0x7b, 0xcc, 0x22, 0x37, 0x44, 0x2b, + 0xf3, 0xbe, 0x89, 0x47, 0xe4, 0x4b, 0x28, 0xb0, 0x73, 0xe1, 0xc0, 0x9a, 0xf9, 0xe9, 0xf3, 0xd9, + 0x5b, 0xbf, 0x47, 0xa9, 0x27, 0xfa, 0x07, 0x29, 0xb5, 0x6d, 0x28, 0x27, 0x63, 0x52, 0x81, 0xf5, + 0x4f, 0xee, 0x1e, 0x1c, 0x77, 0xea, 0x97, 0x48, 0x19, 0xd6, 0xbe, 0xb0, 0x1e, 0x76, 0xea, 0x4a, + 0x93, 0x41, 0x75, 0x2e, 0x16, 0x52, 0x87, 0xe2, 0x39, 0x9d, 0xc6, 0xaa, 0xf9, 0x27, 0xb9, 0x0f, + 0xeb, 0x32, 0x67, 0x85, 0xdc, 0xad, 0x2c, 0x09, 0xf6, 0x0b, 0x1f, 0x28, 0xed, 0x6a, 0xd2, 0x02, + 0x62, 0x4a, 0xab, 0xc1, 0x66, 0xb6, 0xae, 0xad, 0x1d, 0x50, 0x33, 0x1b, 0xb9, 0xd0, 0xd3, 0x8e, + 0x75, 0x84, 0x92, 0x37, 0xa0, 0x78, 0x74, 0x88, 0x8a, 0xcd, 0xa7, 0x55, 0x78, 0x79, 0x31, 0xf6, + 0x63, 0xea, 0x4f, 0x9c, 0x3e, 0x25, 0x3f, 0x14, 0xa1, 0xf4, 0xb1, 0xcf, 0xdb, 0x8e, 0xbc, 0x9f, + 0x33, 0x8d, 0xcd, 0xbc, 0x1b, 0xb5, 0x1f, 0x0b, 0x4f, 0xfe, 0xf8, 0xf3, 0xa7, 0xc2, 0xf7, 0x05, + 0xed, 0xbb, 0x82, 0x31, 0xb9, 0x93, 0x3c, 0x41, 0xff, 0xf4, 0x00, 0x19, 0xb3, 0xcc, 0xcd, 0x7b, + 0x61, 0xcc, 0xb2, 0xd7, 0x2c, 0x0e, 0x33, 0xce, 0xbb, 0x30, 0x02, 0xea, 0xd9, 0xbe, 0x1d, 0x32, + 0xdf, 0x98, 0x45, 0x73, 0x0b, 0xb3, 0x8c, 0x87, 0x71, 0x34, 0x67, 0xfc, 0x64, 0x9c, 0x59, 0xff, + 0xfb, 0xe2, 0xc3, 0x41, 0xd6, 0xb0, 0x1f, 0xe2, 0xc0, 0xf3, 0x29, 0xe2, 0x8d, 0xd6, 0x85, 0x3c, + 0x24, 0xb3, 0x2d, 0x58, 0xe4, 0x09, 0x16, 0x0f, 0x0a, 0x16, 0x36, 0x64, 0x45, 0x92, 0x5f, 0x15, + 0x00, 0x59, 0x91, 0x36, 0x1b, 0x4c, 0xff, 0x87, 0xaa, 0xb4, 0x44, 0x51, 0x6e, 0x68, 0xdb, 0x4b, + 0x4a, 0xb2, 0xaf, 0xb4, 0xc8, 0x6f, 0x28, 0xb6, 0x1d, 0x8d, 0xce, 0x9f, 0xb7, 0x85, 0xf2, 0xdc, + 0x68, 0x9a, 0x21, 0x84, 0xbe, 0xad, 0xdd, 0x58, 0xd6, 0x3b, 0x3d, 0x54, 0x88, 0x6a, 0x77, 0x15, + 0xf2, 0x04, 0x6f, 0x9b, 0x03, 0xc6, 0xce, 0x23, 0x8f, 0x6c, 0xe9, 0xfc, 0x27, 0x86, 0xfe, 0xd9, + 0x20, 0xa6, 0xcb, 0x9f, 0x30, 0x5d, 0xe8, 0xd8, 0x25, 0x6f, 0x2e, 0xed, 0x61, 0xfe, 0xeb, 0xe4, + 0x82, 0xfc, 0xac, 0xc0, 0xda, 0x81, 0x13, 0x84, 0x24, 0x4f, 0xd4, 0xf9, 0x65, 0xbe, 0x25, 0x64, + 0x5e, 0x27, 0xcb, 0xea, 0x7a, 0x5b, 0x21, 0xbf, 0x60, 0x9a, 0x1e, 0x7a, 0x83, 0x17, 0x5f, 0xd2, + 0x3b, 0x42, 0xe3, 0x3b, 0xcd, 0x15, 0x53, 0xc9, 0x5b, 0xf0, 0x1b, 0x28, 0xdd, 0xa3, 0x23, 0x8a, + 0x52, 0x9f, 0xa9, 0x68, 0x2e, 0x09, 0x71, 0x35, 0x5b, 0xab, 0x56, 0xf3, 0x29, 0x56, 0xb3, 0xd3, + 0x7f, 0xc4, 0x88, 0xfe, 0xaf, 0xa7, 0xa1, 0x34, 0x5d, 0x3e, 0xab, 0x89, 0xba, 0xff, 0x88, 0xd7, + 0xfa, 0x42, 0xd8, 0x57, 0xe4, 0xd6, 0x32, 0x61, 0x14, 0xd5, 0x18, 0x33, 0x79, 0x9d, 0x9c, 0xbe, + 0xa2, 0xd5, 0x8d, 0x89, 0x99, 0xe2, 0xf9, 0xda, 0xbe, 0x7c, 0x5c, 0x4e, 0x09, 0x79, 0x66, 0x89, + 0xf7, 0x66, 0x99, 0x1b, 0xfa, 0x85, 0x44, 0xb4, 0xb2, 0x81, 0x85, 0x6a, 0x6e, 0xe0, 0xdb, 0x4a, + 0x5b, 0x3d, 0xad, 0xa4, 0x95, 0xeb, 0x95, 0xc4, 0x3f, 0x83, 0xbd, 0xbf, 0x02, 0x00, 0x00, 0xff, + 0xff, 0x9e, 0x8d, 0xf0, 0x8e, 0xc7, 0x0c, 0x00, 0x00, } diff --git a/examples/examplepb/a_bit_of_everything.proto b/examples/examplepb/a_bit_of_everything.proto index 406023ad010..c1a5a2ffa25 100644 --- a/examples/examplepb/a_bit_of_everything.proto +++ b/examples/examplepb/a_bit_of_everything.proto @@ -36,6 +36,12 @@ message ABitOfEverything { sint32 sint32_value = 17; sint64 sint64_value = 18; repeated string repeated_string_value = 19; + + oneof oneof_value { + EmptyMessage oneof_empty = 20; + string oneof_string = 21; + } + map map_value = 22; } message EmptyMessage { From 6e8e8f3d38ad0364606934174a2ffb6fdc1f2e44 Mon Sep 17 00:00:00 2001 From: Yuki Yugui Sonoda Date: Mon, 9 May 2016 12:44:14 +0900 Subject: [PATCH 4/4] Add tests --- runtime/marshal_json_test.go | 198 ++++++++++++++++++ runtime/marshal_jsonpb_test.go | 356 +++++++++++++++++++++++++++++++++ runtime/marshaler.go | 73 ++----- runtime/marshaler_test.go | 119 +++++++++++ 4 files changed, 695 insertions(+), 51 deletions(-) create mode 100644 runtime/marshal_json_test.go create mode 100644 runtime/marshal_jsonpb_test.go create mode 100644 runtime/marshaler_test.go diff --git a/runtime/marshal_json_test.go b/runtime/marshal_json_test.go new file mode 100644 index 00000000000..44165e31b06 --- /dev/null +++ b/runtime/marshal_json_test.go @@ -0,0 +1,198 @@ +package runtime_test + +import ( + "bytes" + "encoding/json" + "reflect" + "strings" + "testing" + + "github.com/gengo/grpc-gateway/examples/examplepb" + "github.com/gengo/grpc-gateway/runtime" +) + +func TestJSONBuiltinMarshal(t *testing.T) { + var m runtime.JSONBuiltin + msg := examplepb.SimpleMessage{ + Id: "foo", + } + + buf, err := m.Marshal(&msg) + if err != nil { + t.Errorf("m.Marshal(%v) failed with %v; want success", &msg, err) + } + + var got examplepb.SimpleMessage + if err := json.Unmarshal(buf, &got); err != nil { + t.Errorf("json.Unmarshal(%q, &got) failed with %v; want success", buf, err) + } + if want := msg; !reflect.DeepEqual(got, want) { + t.Errorf("got = %v; want %v", &got, &want) + } +} + +func TestJSONBuiltinMarshalPrimitive(t *testing.T) { + var m runtime.JSONBuiltin + for _, v := range []interface{}{ + "", + "foo", + 1, + 0, + -1, + -0.0, + 1.5, + } { + buf, err := m.Marshal(v) + if err != nil { + t.Errorf("m.Marshal(%v) failed with %v; want success", v, err) + } + + dest := reflect.New(reflect.TypeOf(v)) + if err := json.Unmarshal(buf, dest.Interface()); err != nil { + t.Errorf("json.Unmarshal(%q, unmarshaled) failed with %v; want success", buf, err) + } + if got, want := dest.Elem().Interface(), v; !reflect.DeepEqual(got, want) { + t.Errorf("got = %v; want %v", &got, &want) + } + } +} + +func TestJSONBuiltinsnmarshal(t *testing.T) { + var ( + m runtime.JSONBuiltin + got examplepb.SimpleMessage + + data = []byte(`{"id": "foo"}`) + ) + if err := m.Unmarshal(data, &got); err != nil { + t.Errorf("m.Unmarshal(%q, &got) failed with %v; want success", data, err) + } + + want := examplepb.SimpleMessage{ + Id: "foo", + } + if !reflect.DeepEqual(got, want) { + t.Errorf("got = %v; want = %v", &got, &want) + } +} + +func TestJSONBuiltinUnmarshalPrimitive(t *testing.T) { + var m runtime.JSONBuiltin + for _, spec := range []struct { + data string + want interface{} + }{ + {data: `""`, want: ""}, + {data: `"foo"`, want: "foo"}, + {data: `1`, want: 1}, + {data: `0`, want: 0}, + {data: `-1`, want: -1}, + {data: `-0.0`, want: -0.0}, + {data: `1.5`, want: 1.5}, + } { + dest := reflect.New(reflect.TypeOf(spec.want)) + if err := m.Unmarshal([]byte(spec.data), dest.Interface()); err != nil { + t.Errorf("m.Unmarshal(%q, dest) failed with %v; want success", spec.data, err) + } + + if got, want := dest.Elem().Interface(), spec.want; !reflect.DeepEqual(got, want) { + t.Errorf("got = %v; want = %v", got, want) + } + } +} + +func TestJSONBuiltinEncoder(t *testing.T) { + var m runtime.JSONBuiltin + msg := examplepb.SimpleMessage{ + Id: "foo", + } + + var buf bytes.Buffer + enc := m.NewEncoder(&buf) + if err := enc.Encode(&msg); err != nil { + t.Errorf("enc.Encode(%v) failed with %v; want success", &msg, err) + } + + var got examplepb.SimpleMessage + if err := json.Unmarshal(buf.Bytes(), &got); err != nil { + t.Errorf("json.Unmarshal(%q, &got) failed with %v; want success", buf.String(), err) + } + if want := msg; !reflect.DeepEqual(got, want) { + t.Errorf("got = %v; want %v", &got, &want) + } +} + +func TestJSONBuiltinEncoderPrimitive(t *testing.T) { + var m runtime.JSONBuiltin + for _, v := range []interface{}{ + "", + "foo", + 1, + 0, + -1, + -0.0, + 1.5, + } { + var buf bytes.Buffer + enc := m.NewEncoder(&buf) + if err := enc.Encode(v); err != nil { + t.Errorf("enc.Encode(%v) failed with %v; want success", v, err) + } + + dest := reflect.New(reflect.TypeOf(v)) + if err := json.Unmarshal(buf.Bytes(), dest.Interface()); err != nil { + t.Errorf("json.Unmarshal(%q, unmarshaled) failed with %v; want success", buf.String(), err) + } + if got, want := dest.Elem().Interface(), v; !reflect.DeepEqual(got, want) { + t.Errorf("got = %v; want %v", &got, &want) + } + } +} + +func TestJSONBuiltinDecoder(t *testing.T) { + var ( + m runtime.JSONBuiltin + got examplepb.SimpleMessage + + data = `{"id": "foo"}` + ) + r := strings.NewReader(data) + dec := m.NewDecoder(r) + if err := dec.Decode(&got); err != nil { + t.Errorf("m.Unmarshal(&got) failed with %v; want success", err) + } + + want := examplepb.SimpleMessage{ + Id: "foo", + } + if !reflect.DeepEqual(got, want) { + t.Errorf("got = %v; want = %v", &got, &want) + } +} + +func TestJSONBuiltinDecoderPrimitive(t *testing.T) { + var m runtime.JSONBuiltin + for _, spec := range []struct { + data string + want interface{} + }{ + {data: `""`, want: ""}, + {data: `"foo"`, want: "foo"}, + {data: `1`, want: 1}, + {data: `0`, want: 0}, + {data: `-1`, want: -1}, + {data: `-0.0`, want: -0.0}, + {data: `1.5`, want: 1.5}, + } { + r := strings.NewReader(spec.data) + dec := m.NewDecoder(r) + dest := reflect.New(reflect.TypeOf(spec.want)) + if err := dec.Decode(dest.Interface()); err != nil { + t.Errorf("dec.Decode(dest) failed with %v; want success; data=%q", err, spec.data) + } + + if got, want := dest.Elem().Interface(), spec.want; !reflect.DeepEqual(got, want) { + t.Errorf("got = %v; want = %v", got, want) + } + } +} diff --git a/runtime/marshal_jsonpb_test.go b/runtime/marshal_jsonpb_test.go new file mode 100644 index 00000000000..de401f1bc19 --- /dev/null +++ b/runtime/marshal_jsonpb_test.go @@ -0,0 +1,356 @@ +package runtime_test + +import ( + "bytes" + "reflect" + "strings" + "testing" + + "github.com/gengo/grpc-gateway/examples/examplepb" + "github.com/gengo/grpc-gateway/runtime" + "github.com/golang/protobuf/jsonpb" +) + +func TestJSONPbMarshal(t *testing.T) { + msg := examplepb.ABitOfEverything{ + Uuid: "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", + Nested: []*examplepb.ABitOfEverything_Nested{ + { + Name: "foo", + Amount: 12345, + }, + }, + Uint64Value: 0xFFFFFFFFFFFFFFFF, + EnumValue: examplepb.NumericEnum_ONE, + OneofValue: &examplepb.ABitOfEverything_OneofString{ + OneofString: "bar", + }, + MapValue: map[string]examplepb.NumericEnum{ + "a": examplepb.NumericEnum_ONE, + "b": examplepb.NumericEnum_ZERO, + }, + } + + for _, spec := range []struct { + enumsAsInts, emitDefaults bool + indent string + origName bool + verifier func(json string) + }{ + { + verifier: func(json string) { + if strings.ContainsAny(json, " \t\r\n") { + t.Errorf("strings.ContainsAny(%q, %q) = true; want false", json, " \t\r\n") + } + if !strings.Contains(json, "ONE") { + t.Errorf(`strings.Contains(%q, "ONE") = false; want true`, json) + } + if want := "uint64Value"; !strings.Contains(json, want) { + t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want) + } + }, + }, + { + enumsAsInts: true, + verifier: func(json string) { + if strings.Contains(json, "ONE") { + t.Errorf(`strings.Contains(%q, "ONE") = true; want false`, json) + } + }, + }, + { + emitDefaults: true, + verifier: func(json string) { + if want := `"sfixed32Value"`; !strings.Contains(json, want) { + t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want) + } + }, + }, + { + indent: "\t\t", + verifier: func(json string) { + if want := "\t\t\"amount\":"; !strings.Contains(json, want) { + t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want) + } + }, + }, + { + origName: true, + verifier: func(json string) { + if want := "uint64_value"; !strings.Contains(json, want) { + t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want) + } + }, + }, + } { + m := runtime.JSONPb{ + EnumsAsInts: spec.enumsAsInts, + EmitDefaults: spec.emitDefaults, + Indent: spec.indent, + OrigName: spec.origName, + } + buf, err := m.Marshal(&msg) + if err != nil { + t.Errorf("m.Marshal(%v) failed with %v; want success; spec=%v", &msg, err, spec) + } + + var got examplepb.ABitOfEverything + if err := jsonpb.UnmarshalString(string(buf), &got); err != nil { + t.Errorf("jsonpb.UnmarshalString(%q, &got) failed with %v; want success; spec=%v", string(buf), err, spec) + } + if want := msg; !reflect.DeepEqual(got, want) { + t.Errorf("got = %v; want %v; spec=%v", &got, &want, spec) + } + if spec.verifier != nil { + spec.verifier(string(buf)) + } + } +} + +func TestJSONPbUnmarshal(t *testing.T) { + var ( + m runtime.JSONPb + got examplepb.ABitOfEverything + ) + for _, data := range []string{ + `{ + "uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", + "nested": [ + {"name": "foo", "amount": 12345} + ], + "uint64Value": 18446744073709551615, + "enumValue": "ONE", + "oneofString": "bar", + "mapValue": { + "a": 1, + "b": 0 + } + }`, + `{ + "uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", + "nested": [ + {"name": "foo", "amount": 12345} + ], + "uint64Value": "18446744073709551615", + "enumValue": "ONE", + "oneofString": "bar", + "mapValue": { + "a": 1, + "b": 0 + } + }`, + `{ + "uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", + "nested": [ + {"name": "foo", "amount": 12345} + ], + "uint64Value": 18446744073709551615, + "enumValue": 1, + "oneofString": "bar", + "mapValue": { + "a": 1, + "b": 0 + } + }`, + } { + if err := m.Unmarshal([]byte(data), &got); err != nil { + t.Errorf("m.Unmarshal(%q, &got) failed with %v; want success", data, err) + } + + want := examplepb.ABitOfEverything{ + Uuid: "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", + Nested: []*examplepb.ABitOfEverything_Nested{ + { + Name: "foo", + Amount: 12345, + }, + }, + Uint64Value: 0xFFFFFFFFFFFFFFFF, + EnumValue: examplepb.NumericEnum_ONE, + OneofValue: &examplepb.ABitOfEverything_OneofString{ + OneofString: "bar", + }, + MapValue: map[string]examplepb.NumericEnum{ + "a": examplepb.NumericEnum_ONE, + "b": examplepb.NumericEnum_ZERO, + }, + } + + if !reflect.DeepEqual(got, want) { + t.Errorf("got = %v; want = %v", &got, &want) + } + } +} + +func TestJSONPbEncoder(t *testing.T) { + msg := examplepb.ABitOfEverything{ + Uuid: "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", + Nested: []*examplepb.ABitOfEverything_Nested{ + { + Name: "foo", + Amount: 12345, + }, + }, + Uint64Value: 0xFFFFFFFFFFFFFFFF, + OneofValue: &examplepb.ABitOfEverything_OneofString{ + OneofString: "bar", + }, + MapValue: map[string]examplepb.NumericEnum{ + "a": examplepb.NumericEnum_ONE, + "b": examplepb.NumericEnum_ZERO, + }, + } + + for _, spec := range []struct { + enumsAsInts, emitDefaults bool + indent string + origName bool + verifier func(json string) + }{ + { + verifier: func(json string) { + if strings.ContainsAny(json, " \t\r\n") { + t.Errorf("strings.ContainsAny(%q, %q) = true; want false", json, " \t\r\n") + } + if strings.Contains(json, "ONE") { + t.Errorf(`strings.Contains(%q, "ONE") = true; want false`, json) + } + if want := "uint64Value"; !strings.Contains(json, want) { + t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want) + } + }, + }, + { + enumsAsInts: true, + verifier: func(json string) { + if strings.Contains(json, "ONE") { + t.Errorf(`strings.Contains(%q, "ONE") = true; want false`, json) + } + }, + }, + { + emitDefaults: true, + verifier: func(json string) { + if want := `"sfixed32Value"`; !strings.Contains(json, want) { + t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want) + } + }, + }, + { + indent: "\t\t", + verifier: func(json string) { + if want := "\t\t\"amount\":"; !strings.Contains(json, want) { + t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want) + } + }, + }, + { + origName: true, + verifier: func(json string) { + if want := "uint64_value"; !strings.Contains(json, want) { + t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want) + } + }, + }, + } { + m := runtime.JSONPb{ + EnumsAsInts: spec.enumsAsInts, + EmitDefaults: spec.emitDefaults, + Indent: spec.indent, + OrigName: spec.origName, + } + + var buf bytes.Buffer + enc := m.NewEncoder(&buf) + if err := enc.Encode(&msg); err != nil { + t.Errorf("enc.Encode(%v) failed with %v; want success; spec=%v", &msg, err, spec) + } + + var got examplepb.ABitOfEverything + if err := jsonpb.UnmarshalString(buf.String(), &got); err != nil { + t.Errorf("jsonpb.UnmarshalString(%q, &got) failed with %v; want success; spec=%v", buf.String(), err, spec) + } + if want := msg; !reflect.DeepEqual(got, want) { + t.Errorf("got = %v; want %v; spec=%v", &got, &want, spec) + } + if spec.verifier != nil { + spec.verifier(buf.String()) + } + } +} + +func TestJSONPbDecoder(t *testing.T) { + var ( + m runtime.JSONPb + got examplepb.ABitOfEverything + ) + for _, data := range []string{ + `{ + "uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", + "nested": [ + {"name": "foo", "amount": 12345} + ], + "uint64Value": 18446744073709551615, + "enumValue": "ONE", + "oneofString": "bar", + "mapValue": { + "a": 1, + "b": 0 + } + }`, + `{ + "uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", + "nested": [ + {"name": "foo", "amount": 12345} + ], + "uint64Value": "18446744073709551615", + "enumValue": "ONE", + "oneofString": "bar", + "mapValue": { + "a": 1, + "b": 0 + } + }`, + `{ + "uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", + "nested": [ + {"name": "foo", "amount": 12345} + ], + "uint64Value": 18446744073709551615, + "enumValue": 1, + "oneofString": "bar", + "mapValue": { + "a": 1, + "b": 0 + } + }`, + } { + r := strings.NewReader(data) + dec := m.NewDecoder(r) + if err := dec.Decode(&got); err != nil { + t.Errorf("m.Unmarshal(&got) failed with %v; want success; data=%q", err, data) + } + + want := examplepb.ABitOfEverything{ + Uuid: "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", + Nested: []*examplepb.ABitOfEverything_Nested{ + { + Name: "foo", + Amount: 12345, + }, + }, + Uint64Value: 0xFFFFFFFFFFFFFFFF, + EnumValue: examplepb.NumericEnum_ONE, + OneofValue: &examplepb.ABitOfEverything_OneofString{ + OneofString: "bar", + }, + MapValue: map[string]examplepb.NumericEnum{ + "a": examplepb.NumericEnum_ONE, + "b": examplepb.NumericEnum_ZERO, + }, + } + if !reflect.DeepEqual(got, want) { + t.Errorf("got = %v; want = %v; data = %v", &got, &want, data) + } + } +} diff --git a/runtime/marshaler.go b/runtime/marshaler.go index aa202fb397a..58e327d9284 100644 --- a/runtime/marshaler.go +++ b/runtime/marshaler.go @@ -22,72 +22,36 @@ var ( // exactly match in the registry. // Otherwise, it follows the above logic for "*"/InboundMarshaler/OutboundMarshaler. func MarshalerForRequest(mux *ServeMux, r *http.Request) (inbound Marshaler, outbound Marshaler) { - inbound = nil - outbound = nil - headerVals := r.Header[contentTypeHeader] + headerVals := append(append([]string(nil), r.Header[contentTypeHeader]...), "*") for _, val := range headerVals { - if mux.MIMERegistry != nil && mux.MIMERegistry.mimeMap != nil { - if m, ok := mux.MIMERegistry.mimeMap[val]; ok { - if inbound == nil && m.inbound != nil { - inbound = m.inbound - } - if outbound == nil && m.outbound != nil { - outbound = m.outbound - } - } - } else { - //Nil mimeMap, no need to bother checking for mimeWildcard - if mux.InboundMarshaler == nil { - //Its nil, use our default - inbound = inboundDefaultMarshaler - } else { - inbound = mux.InboundMarshaler + m := mux.MIMERegistry.lookup(val) + if m != nil { + if inbound == nil { + inbound = m.inbound } - - if mux.OutboundMarshaler == nil { - //Its nil, use our default - outbound = outboundDefaultMarshaler - } else { - outbound = mux.OutboundMarshaler + if outbound == nil { + outbound = m.outbound } } - if inbound != nil && outbound != nil { - //Got them both, return + // Got them both, return return inbound, outbound } } - if mux.MIMERegistry != nil && mux.MIMERegistry.mimeMap != nil { - if m, ok := mux.MIMERegistry.mimeMap[mimeWildcard]; ok { - if inbound == nil && m.inbound != nil { - inbound = m.inbound - } - if outbound == nil && m.outbound != nil { - outbound = m.outbound - } - } + if inbound == nil { + inbound = mux.InboundMarshaler } - - //Haven't gotten anywhere with any of the headers or mimeWildcard - //Try to use the mux, otherwise use our default if inbound == nil { - if mux.InboundMarshaler == nil { - //Its nil, use our default - inbound = inboundDefaultMarshaler - } else { - inbound = mux.InboundMarshaler - } + inbound = inboundDefaultMarshaler } if outbound == nil { - if mux.OutboundMarshaler == nil { - //Its nil, use our default - outbound = outboundDefaultMarshaler - } else { - outbound = mux.OutboundMarshaler - } + outbound = mux.OutboundMarshaler + } + if outbound == nil { + outbound = outboundDefaultMarshaler } return inbound, outbound @@ -160,6 +124,13 @@ func (m *MarshalerMIMERegistry) AddOutboundMarshaler(mime string, outbound Marsh } +func (m *MarshalerMIMERegistry) lookup(mime string) *mimeMarshaler { + if m == nil { + return nil + } + return m.mimeMap[mime] +} + // NewMarshalerMIMERegistry returns a new registry of marshalers. // It allows for a mapping of case-sensitive Content-Type MIME type string to runtime.Marshaler interfaces. // diff --git a/runtime/marshaler_test.go b/runtime/marshaler_test.go new file mode 100644 index 00000000000..c416471e7db --- /dev/null +++ b/runtime/marshaler_test.go @@ -0,0 +1,119 @@ +package runtime_test + +import ( + "errors" + "io" + "net/http" + "testing" + + "github.com/gengo/grpc-gateway/runtime" +) + +func TestMarshalerForRequest(t *testing.T) { + r, err := http.NewRequest("GET", "http://example.com", nil) + if err != nil { + t.Fatalf(`http.NewRequest("GET", "http://example.com", nil) failed with %v; want success`, err) + } + r.Header.Set("Content-Type", "application/x-example") + + reg := runtime.NewMarshalerMIMERegistry() + mux := runtime.NewServeMux() + mux.MIMERegistry = reg + + in, out := runtime.MarshalerForRequest(mux, r) + if _, ok := in.(*runtime.JSONBuiltin); !ok { + t.Errorf("in = %#v; want a runtime.JSONBuiltin", in) + } + if _, ok := out.(*runtime.JSONBuiltin); !ok { + t.Errorf("out = %#v; want a runtime.JSONBuiltin", in) + } + + m1 := new(dummyMarshaler) + reg.AddMarshaler("*", m1, m1) + in, out = runtime.MarshalerForRequest(mux, r) + if got, want := in, m1; got != want { + t.Errorf("in = %#v; want %#v", got, want) + } + if got, want := out, m1; got != want { + t.Errorf("out = %#v; want %#v", got, want) + } + + m2 := new(dummyMarshaler) + reg.AddInboundMarshaler("*", m2) + in, out = runtime.MarshalerForRequest(mux, r) + if got, want := in, m2; got != want { + t.Errorf("in = %#v; want %#v", got, want) + } + if got, want := out, m1; got != want { + t.Errorf("out = %#v; want %#v", got, want) + } + + m3 := new(dummyMarshaler) + reg.AddOutboundMarshaler("application/x-example", m3) + in, out = runtime.MarshalerForRequest(mux, r) + if got, want := in, m2; got != want { + t.Errorf("in = %#v; want %#v", got, want) + } + if got, want := out, m3; got != want { + t.Errorf("out = %#v; want %#v", got, want) + } + + m4 := new(dummyMarshaler) + reg.AddInboundMarshaler("application/x-example", m4) + in, out = runtime.MarshalerForRequest(mux, r) + if got, want := in, m4; got != want { + t.Errorf("in = %#v; want %#v", got, want) + } + if got, want := out, m3; got != want { + t.Errorf("out = %#v; want %#v", got, want) + } + + m5, m6 := new(dummyMarshaler), new(dummyMarshaler) + reg.AddMarshaler("application/x-example", m5, m6) + in, out = runtime.MarshalerForRequest(mux, r) + if got, want := in, m5; got != want { + t.Errorf("in = %#v; want %#v", got, want) + } + if got, want := out, m6; got != want { + t.Errorf("out = %#v; want %#v", got, want) + } + + r.Header.Set("Content-Type", "application/x-another") + in, out = runtime.MarshalerForRequest(mux, r) + if got, want := in, m2; got != want { + t.Errorf("in = %#v; want %#v", got, want) + } + if got, want := out, m1; got != want { + t.Errorf("out = %#v; want %#v", got, want) + } +} + +type dummyMarshaler struct{} + +func (dummyMarshaler) ContentType() string { return "" } +func (dummyMarshaler) Marshal(interface{}) ([]byte, error) { + return nil, errors.New("not implemented") +} + +func (dummyMarshaler) Unmarshal([]byte, interface{}) error { + return errors.New("not implemented") +} + +func (dummyMarshaler) NewDecoder(r io.Reader) runtime.Decoder { + return dummyDecoder{} +} +func (dummyMarshaler) NewEncoder(w io.Writer) runtime.Encoder { + return dummyEncoder{} +} + +type dummyDecoder struct{} + +func (dummyDecoder) Decode(interface{}) error { + return errors.New("not implemented") +} + +type dummyEncoder struct{} + +func (dummyEncoder) Encode(interface{}) error { + return errors.New("not implemented") +}