Skip to content

Commit 0353029

Browse files
abicejohanbrandhorst
authored andcommitted
marshal_jsonpb: add check for slice sub types implementing proto.Message (#856)
* marshal_jsonpb: add check for slice sub types implementing proto.Message * Added more tests.
1 parent ff4dc68 commit 0353029

11 files changed

+208
-44
lines changed

examples/clients/responsebody/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ go_library(
1515
"examplepb_response_body_out_response.go",
1616
"examplepb_response_body_req.go",
1717
"response_body_service_api.go",
18+
"response_response_type.go",
1819
],
1920
importpath = "github.com/grpc-ecosystem/grpc-gateway/examples/clients/responsebody",
2021
visibility = ["//visibility:public"],

examples/clients/responsebody/docs/ExamplepbRepeatedResponseBodyOutResponse.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
Name | Type | Description | Notes
55
------------ | ------------- | ------------- | -------------
66
**Data** | **string** | | [optional] [default to null]
7+
**Type_** | [**ResponseResponseType**](ResponseResponseType.md) | | [optional] [default to null]
78

89
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
910

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# ResponseResponseType
2+
3+
## Properties
4+
Name | Type | Description | Notes
5+
------------ | ------------- | ------------- | -------------
6+
7+
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
8+
9+

examples/clients/responsebody/examplepb_repeated_response_body_out_response.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,6 @@ package responsebody
1313
type ExamplepbRepeatedResponseBodyOutResponse struct {
1414

1515
Data string `json:"data,omitempty"`
16+
17+
Type_ ResponseResponseType `json:"type,omitempty"`
1618
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/*
2+
* examples/proto/examplepb/response_body_service.proto
3+
*
4+
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
5+
*
6+
* OpenAPI spec version: version not set
7+
*
8+
* Generated by: https://github.com/swagger-api/swagger-codegen.git
9+
*/
10+
11+
package responsebody
12+
13+
type ResponseResponseType struct {
14+
}

examples/integration/integration_test.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1365,7 +1365,7 @@ func testResponseStrings(t *testing.T, port int) {
13651365
// Run Secondary server with different marshalling
13661366
ch := make(chan error)
13671367
go func() {
1368-
if err := runGateway(ctx, ":8081", runtime.WithMarshalerOption(runtime.MIMEWildcard, &runtime.JSONPb{EmitDefaults: true})); err != nil {
1368+
if err := runGateway(ctx, ":8081", runtime.WithMarshalerOption(runtime.MIMEWildcard, &runtime.JSONPb{EnumsAsInts: false, EmitDefaults: true})); err != nil {
13691369
ch <- fmt.Errorf("cannot run gateway service: %v", err)
13701370
}
13711371
}()
@@ -1387,6 +1387,11 @@ func testResponseStrings(t *testing.T, port int) {
13871387
expectedCode: http.StatusOK,
13881388
expectedBody: `[]`,
13891389
},
1390+
{
1391+
endpoint: fmt.Sprintf("http://localhost:%d/responsebodies/foo", port),
1392+
expectedCode: http.StatusOK,
1393+
expectedBody: `[{"data":"foo","type":"UNKNOWN"}]`,
1394+
},
13901395
} {
13911396
t.Run(strconv.Itoa(i), func(t *testing.T) {
13921397
url := spec.endpoint

examples/proto/examplepb/response_body_service.pb.go

Lines changed: 81 additions & 39 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/proto/examplepb/response_body_service.proto

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,18 @@ message ResponseBodyOut {
1313
}
1414

1515
message RepeatedResponseBodyOut {
16-
message Response { string data = 1; }
16+
message Response {
17+
string data = 1;
18+
enum ResponseType {
19+
// UNKNOWN
20+
UNKNOWN = 0;
21+
// A is 1
22+
A = 1;
23+
// B is 2
24+
B = 2;
25+
}
26+
ResponseType type = 3;
27+
}
1728
repeated Response response = 2;
1829
}
1930

examples/proto/examplepb/response_body_service.swagger.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,16 @@
9595
}
9696
},
9797
"definitions": {
98+
"ResponseResponseType": {
99+
"type": "string",
100+
"enum": [
101+
"UNKNOWN",
102+
"A",
103+
"B"
104+
],
105+
"default": "UNKNOWN",
106+
"title": "- UNKNOWN: UNKNOWN\n - A: A is 1\n - B: B is 2"
107+
},
98108
"examplepbRepeatedResponseBodyOut": {
99109
"type": "object",
100110
"properties": {
@@ -111,6 +121,9 @@
111121
"properties": {
112122
"data": {
113123
"type": "string"
124+
},
125+
"type": {
126+
"$ref": "#/definitions/ResponseResponseType"
114127
}
115128
}
116129
},

runtime/marshal_jsonpb.go

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ func (j *JSONPb) marshalTo(w io.Writer, v interface{}) error {
5050
return (*jsonpb.Marshaler)(j).Marshal(w, p)
5151
}
5252

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+
5358
// marshalNonProto marshals a non-message field of a protobuf message.
5459
// This function does not correctly marshals arbitrary data structure into JSON,
5560
// but it is only capable of marshaling non-message field values of protobuf,
@@ -67,8 +72,38 @@ func (j *JSONPb) marshalNonProtoField(v interface{}) ([]byte, error) {
6772
rv = rv.Elem()
6873
}
6974

70-
if rv.Kind() == reflect.Slice && rv.IsNil() && j.EmitDefaults {
71-
return []byte("[]"), nil
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+
}
72107
}
73108

74109
if rv.Kind() == reflect.Map {

0 commit comments

Comments
 (0)