Skip to content

Commit 7868a09

Browse files
authored
Merge pull request #13 from jwfang/json-print-opt
ResponseToJsonTranslator supports JsonPrintOptions
2 parents 3a90dfd + 44db136 commit 7868a09

File tree

3 files changed

+110
-14
lines changed

3 files changed

+110
-14
lines changed

src/include/grpc_transcoding/response_to_json_translator.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include "google/protobuf/io/zero_copy_stream.h"
2121
#include "google/protobuf/stubs/status.h"
22+
#include "google/protobuf/util/json_util.h"
2223
#include "google/protobuf/util/type_resolver.h"
2324
#include "message_reader.h"
2425
#include "message_stream.h"
@@ -64,9 +65,15 @@ class ResponseToJsonTranslator : public MessageStream {
6465
// streaming - whether this is a streaming call or not
6566
// in - the input stream of delimited proto message(s) as in the gRPC wire
6667
// format (http://www.grpc.io/docs/guides/wire.html)
68+
// json_print_options - control various aspects for the generated JSON, such
69+
// as indentation, weather to omit fields with default values, etc (
70+
// https://developers.google.com/protocol-buffers/docs/reference/cpp/
71+
// google.protobuf.util.json_util#JsonPrintOptions
6772
ResponseToJsonTranslator(
6873
::google::protobuf::util::TypeResolver* type_resolver,
69-
std::string type_url, bool streaming, TranscoderInputStream* in);
74+
std::string type_url, bool streaming, TranscoderInputStream* in,
75+
const ::google::protobuf::util::JsonPrintOptions&
76+
json_print_options = ::google::protobuf::util::JsonPrintOptions());
7077

7178
// MessageStream implementation
7279
bool NextMessage(std::string* message);
@@ -80,6 +87,7 @@ class ResponseToJsonTranslator : public MessageStream {
8087

8188
::google::protobuf::util::TypeResolver* type_resolver_;
8289
std::string type_url_;
90+
const ::google::protobuf::util::JsonPrintOptions json_print_options_;
8391
bool streaming_;
8492

8593
// A MessageReader to extract full messages

src/response_to_json_translator.cc

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020

2121
#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
2222
#include "google/protobuf/stubs/status.h"
23-
#include "google/protobuf/util/json_util.h"
2423
#include "google/protobuf/util/type_resolver.h"
2524

2625
namespace google {
@@ -30,9 +29,11 @@ namespace transcoding {
3029

3130
ResponseToJsonTranslator::ResponseToJsonTranslator(
3231
::google::protobuf::util::TypeResolver* type_resolver, std::string type_url,
33-
bool streaming, TranscoderInputStream* in)
32+
bool streaming, TranscoderInputStream* in,
33+
const ::google::protobuf::util::JsonPrintOptions& json_print_options)
3434
: type_resolver_(type_resolver),
3535
type_url_(std::move(type_url)),
36+
json_print_options_(json_print_options),
3637
streaming_(streaming),
3738
reader_(in),
3839
first_(true),
@@ -118,7 +119,7 @@ bool ResponseToJsonTranslator::TranslateMessage(
118119

119120
// Do the actual translation.
120121
status_ = ::google::protobuf::util::BinaryToJsonStream(
121-
type_resolver_, type_url_, proto_in, &json_stream);
122+
type_resolver_, type_url_, proto_in, &json_stream, json_print_options_);
122123
if (!status_.ok()) {
123124
return false;
124125
}

test/response_to_json_translator_test.cc

Lines changed: 97 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,17 @@ class ResponseToJsonTranslatorTestRun {
5757
// input - the input to be passed to the MessageReader,
5858
// expected - the expected translated json chunks as the input is processed,
5959
ResponseToJsonTranslatorTestRun(pbutil::TypeResolver* type_resolver,
60-
bool streaming, const std::string& type_url,
61-
const std::string& input,
62-
const std::vector<ExpectedAt>& expected)
60+
bool streaming, const std::string& type_url,
61+
const pbutil::JsonPrintOptions& json_print_options,
62+
const std::string& input,
63+
const std::vector<ExpectedAt>& expected)
6364
: input_(input),
6465
expected_(expected),
6566
streaming_(streaming),
6667
input_stream_(new TestZeroCopyInputStream()),
6768
translator_(new ResponseToJsonTranslator(
68-
type_resolver, type_url, streaming_, input_stream_.get())),
69+
type_resolver, type_url, streaming_, input_stream_.get(),
70+
json_print_options)),
6971
position_(0),
7072
next_expected_(std::begin(expected_)) {}
7173

@@ -186,19 +188,21 @@ class ResponseToJsonTranslatorTestCase {
186188
// input - the input to be passed to the MessageReader,
187189
// expected - the expected translated json chunks as the input is processed,
188190
ResponseToJsonTranslatorTestCase(pbutil::TypeResolver* type_resolver,
189-
bool streaming, const std::string& type_url,
190-
std::string input,
191-
std::vector<ExpectedAt> expected)
191+
bool streaming, const std::string& type_url,
192+
const pbutil::JsonPrintOptions& json_print_options,
193+
std::string input, std::vector<ExpectedAt> expected)
192194
: type_resolver_(type_resolver),
193195
streaming_(streaming),
194196
type_url_(type_url),
197+
json_print_options_(json_print_options),
195198
input_(std::move(input)),
196199
expected_(std::move(expected)) {}
197200

198201
std::unique_ptr<ResponseToJsonTranslatorTestRun> NewRun() {
199202
return std::unique_ptr<ResponseToJsonTranslatorTestRun>(
200203
new ResponseToJsonTranslatorTestRun(type_resolver_, streaming_,
201-
type_url_, input_, expected_));
204+
type_url_, json_print_options_,
205+
input_, expected_));
202206
}
203207

204208
// Runs the test for different partitions of the input.
@@ -234,6 +238,7 @@ class ResponseToJsonTranslatorTestCase {
234238
pbutil::TypeResolver* type_resolver_;
235239
bool streaming_;
236240
std::string type_url_;
241+
pbutil::JsonPrintOptions json_print_options_;
237242

238243
// The entire input including message delimiters
239244
std::string input_;
@@ -261,6 +266,21 @@ class ResponseToJsonTranslatorTest : public ::testing::Test {
261266
type_url_ = "type.googleapis.com/" + type_name;
262267
}
263268

269+
// Sets json print options type for used in this test. Must be used before
270+
// Build().
271+
void SetJsonPrintOptions(const pbutil::JsonPrintOptions& json_print_options) {
272+
json_print_options_ = json_print_options;
273+
}
274+
275+
// Sets whether always print primitive fields for default values. Must be used
276+
// before Build(). The default is false.
277+
void SetJsonAlwaysPrintPrimitiveFields(bool always_print_primitive_fields) {
278+
pbutil::JsonPrintOptions json_print_options;
279+
json_print_options.always_print_primitive_fields =
280+
always_print_primitive_fields;
281+
SetJsonPrintOptions(json_print_options);
282+
}
283+
264284
// Sets whether this is a streaming call or not. Must be used before Build().
265285
// The default is non-streaming.
266286
void SetStreaming(bool streaming) { streaming_ = streaming; }
@@ -285,15 +305,16 @@ class ResponseToJsonTranslatorTest : public ::testing::Test {
285305

286306
return std::unique_ptr<ResponseToJsonTranslatorTestCase>(
287307
new ResponseToJsonTranslatorTestCase(
288-
type_helper_->Resolver(), streaming_, type_url_, std::move(input),
289-
std::move(expected)));
308+
type_helper_->Resolver(), streaming_, type_url_, json_print_options_,
309+
std::move(input), std::move(expected)));
290310
}
291311

292312
private:
293313
::google::api::Service service_;
294314
std::unique_ptr<TypeHelper> type_helper_;
295315

296316
std::string type_url_;
317+
pbutil::JsonPrintOptions json_print_options_;
297318
bool streaming_;
298319

299320
// The entire input
@@ -316,6 +337,20 @@ TEST_F(ResponseToJsonTranslatorTest, Simple) {
316337
EXPECT_TRUE(tc->Test(4, 0.5));
317338
}
318339

340+
TEST_F(ResponseToJsonTranslatorTest, SimpleAlwaysPrintPrimitiveFields) {
341+
ASSERT_TRUE(LoadService("bookstore_service.pb.txt"));
342+
SetMessageType("Shelf");
343+
SetJsonAlwaysPrintPrimitiveFields(true);
344+
AddMessage<Shelf>(R"(name : "" theme : "")",
345+
R"({ "name" : "", "theme" : ""})");
346+
347+
auto tc = Build();
348+
EXPECT_TRUE(tc->Test(1, 1.0));
349+
EXPECT_TRUE(tc->Test(2, 1.0));
350+
EXPECT_TRUE(tc->Test(3, 1.0));
351+
EXPECT_TRUE(tc->Test(4, 0.5));
352+
}
353+
319354
TEST_F(ResponseToJsonTranslatorTest, Nested) {
320355
ASSERT_TRUE(LoadService("bookstore_service.pb.txt"));
321356
SetMessageType("Book");
@@ -355,6 +390,46 @@ TEST_F(ResponseToJsonTranslatorTest, Nested) {
355390
EXPECT_TRUE(tc->Test(3, 0.2));
356391
}
357392

393+
TEST_F(ResponseToJsonTranslatorTest, NestedAlwaysPrintPrimitiveFields) {
394+
ASSERT_TRUE(LoadService("bookstore_service.pb.txt"));
395+
SetMessageType("Book");
396+
SetJsonAlwaysPrintPrimitiveFields(true);
397+
AddMessage<Book>(
398+
R"(
399+
name : ""
400+
author : ""
401+
title : ""
402+
author_info {
403+
first_name : ""
404+
last_name : ""
405+
bio {
406+
year_born : 0
407+
year_died : 0
408+
text : ""
409+
}
410+
}
411+
)",
412+
R"({
413+
"author" : "",
414+
"name" : "",
415+
"title" : "",
416+
"authorInfo" : {
417+
"firstName" : "",
418+
"lastName" : "",
419+
"bio" : {
420+
"yearBorn" : "0",
421+
"yearDied" : "0",
422+
"text" : ""
423+
}
424+
}
425+
})");
426+
427+
auto tc = Build();
428+
EXPECT_TRUE(tc->Test(1, 1.0));
429+
EXPECT_TRUE(tc->Test(2, 1.0));
430+
EXPECT_TRUE(tc->Test(3, 0.2));
431+
}
432+
358433
TEST_F(ResponseToJsonTranslatorTest, Empty) {
359434
ASSERT_TRUE(LoadService("bookstore_service.pb.txt"));
360435
SetMessageType("Shelf");
@@ -365,6 +440,18 @@ TEST_F(ResponseToJsonTranslatorTest, Empty) {
365440
EXPECT_TRUE(tc->Test(2, 1.0));
366441
}
367442

443+
TEST_F(ResponseToJsonTranslatorTest, EmptyAlwaysPrintPrimitiveFields) {
444+
ASSERT_TRUE(LoadService("bookstore_service.pb.txt"));
445+
SetMessageType("Shelf");
446+
SetJsonAlwaysPrintPrimitiveFields(true);
447+
AddMessage<Shelf>(R"()",
448+
R"({ "name" : "", "theme" : ""})");
449+
450+
auto tc = Build();
451+
EXPECT_TRUE(tc->Test(1, 1.0));
452+
EXPECT_TRUE(tc->Test(2, 1.0));
453+
}
454+
368455
TEST_F(ResponseToJsonTranslatorTest, DifferentSizes) {
369456
ASSERT_TRUE(LoadService("bookstore_service.pb.txt"));
370457
SetMessageType("Shelf");

0 commit comments

Comments
 (0)