From 773d8c3329d1a28732d9f9c4b21c02e302052e4f Mon Sep 17 00:00:00 2001 From: stone4774 Date: Mon, 19 Mar 2018 15:57:07 +0800 Subject: Fix bug: whether always_print_enums_as_ints is true or false, it always print the default value of enums as strings --- .../util/internal/default_value_objectwriter.cc | 31 ++++++++++++---------- .../util/internal/default_value_objectwriter.h | 20 +++++++++++--- src/google/protobuf/util/json_format_proto3.proto | 6 +++++ src/google/protobuf/util/json_util.cc | 2 ++ src/google/protobuf/util/json_util_test.cc | 24 +++++++++++++++++ 5 files changed, 66 insertions(+), 17 deletions(-) diff --git a/src/google/protobuf/util/internal/default_value_objectwriter.cc b/src/google/protobuf/util/internal/default_value_objectwriter.cc index 95b3a17d..32e2429b 100644 --- a/src/google/protobuf/util/internal/default_value_objectwriter.cc +++ b/src/google/protobuf/util/internal/default_value_objectwriter.cc @@ -66,6 +66,7 @@ DefaultValueObjectWriter::DefaultValueObjectWriter( root_(NULL), suppress_empty_list_(false), preserve_proto_field_names_(false), + use_ints_for_enums_(false), field_scrub_callback_(NULL), ow_(ow) {} @@ -200,10 +201,10 @@ DefaultValueObjectWriter::Node* DefaultValueObjectWriter::CreateNewNode( DefaultValueObjectWriter::Node* DefaultValueObjectWriter::CreateNewNode( const string& name, const google::protobuf::Type* type, NodeKind kind, const DataPiece& data, bool is_placeholder, const std::vector& path, - bool suppress_empty_list, bool preserve_proto_field_names, + bool suppress_empty_list, bool preserve_proto_field_names, bool use_ints_for_enums, FieldScrubCallBack* field_scrub_callback) { return new Node(name, type, kind, data, is_placeholder, path, - suppress_empty_list, preserve_proto_field_names, + suppress_empty_list, preserve_proto_field_names, use_ints_for_enums, field_scrub_callback); } @@ -220,12 +221,13 @@ DefaultValueObjectWriter::Node::Node( path_(path), suppress_empty_list_(suppress_empty_list), preserve_proto_field_names_(false), + use_ints_for_enums_(false), field_scrub_callback_(field_scrub_callback) {} DefaultValueObjectWriter::Node::Node( const string& name, const google::protobuf::Type* type, NodeKind kind, const DataPiece& data, bool is_placeholder, const std::vector& path, - bool suppress_empty_list, bool preserve_proto_field_names, + bool suppress_empty_list, bool preserve_proto_field_names, bool use_ints_for_enums, FieldScrubCallBack* field_scrub_callback) : name_(name), type_(type), @@ -236,6 +238,7 @@ DefaultValueObjectWriter::Node::Node( path_(path), suppress_empty_list_(suppress_empty_list), preserve_proto_field_names_(preserve_proto_field_names), + use_ints_for_enums_(use_ints_for_enums), field_scrub_callback_(field_scrub_callback) {} DefaultValueObjectWriter::Node* DefaultValueObjectWriter::Node::FindChild( @@ -408,9 +411,9 @@ void DefaultValueObjectWriter::Node::PopulateChildren( google::protobuf::scoped_ptr child(new Node( preserve_proto_field_names_ ? field.name() : field.json_name(), field_type, kind, - kind == PRIMITIVE ? CreateDefaultDataPieceForField(field, typeinfo) + kind == PRIMITIVE ? CreateDefaultDataPieceForField(field, typeinfo, use_ints_for_enums_) : DataPiece::NullData(), - true, path, suppress_empty_list_, preserve_proto_field_names_, + true, path, suppress_empty_list_, preserve_proto_field_names_, use_ints_for_enums_, field_scrub_callback_)); new_children.push_back(child.release()); } @@ -435,7 +438,7 @@ void DefaultValueObjectWriter::MaybePopulateChildrenOfAny(Node* node) { } DataPiece DefaultValueObjectWriter::FindEnumDefault( - const google::protobuf::Field& field, const TypeInfo* typeinfo) { + const google::protobuf::Field& field, const TypeInfo* typeinfo, bool use_ints_for_enums) { if (!field.default_value().empty()) return DataPiece(field.default_value(), true); @@ -448,12 +451,12 @@ DataPiece DefaultValueObjectWriter::FindEnumDefault( } // We treat the first value as the default if none is specified. return enum_type->enumvalue_size() > 0 - ? DataPiece(enum_type->enumvalue(0).name(), true) + ? (use_ints_for_enums ? DataPiece(0) : DataPiece(enum_type->enumvalue(0).name(), true)) : DataPiece::NullData(); } DataPiece DefaultValueObjectWriter::CreateDefaultDataPieceForField( - const google::protobuf::Field& field, const TypeInfo* typeinfo) { + const google::protobuf::Field& field, const TypeInfo* typeinfo, bool use_ints_for_enums) { switch (field.kind()) { case google::protobuf::Field_Kind_TYPE_DOUBLE: { return DataPiece(ConvertTo( @@ -496,7 +499,7 @@ DataPiece DefaultValueObjectWriter::CreateDefaultDataPieceForField( field.default_value(), &DataPiece::ToUint32, static_cast(0))); } case google::protobuf::Field_Kind_TYPE_ENUM: { - return FindEnumDefault(field, typeinfo); + return FindEnumDefault(field, typeinfo, use_ints_for_enums); } default: { return DataPiece::NullData(); } } @@ -508,7 +511,7 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::StartObject( std::vector path; root_.reset(CreateNewNode(string(name), &type_, OBJECT, DataPiece::NullData(), false, path, - suppress_empty_list_, preserve_proto_field_names_, + suppress_empty_list_, preserve_proto_field_names_, use_ints_for_enums_, field_scrub_callback_.get())); root_->PopulateChildren(typeinfo_); current_ = root_.get(); @@ -526,7 +529,7 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::StartObject( : NULL), OBJECT, DataPiece::NullData(), false, child == NULL ? current_->path() : child->path(), - suppress_empty_list_, preserve_proto_field_names_, + suppress_empty_list_, preserve_proto_field_names_, use_ints_for_enums_, field_scrub_callback_.get())); child = node.get(); current_->AddChild(node.release()); @@ -559,7 +562,7 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::StartList( std::vector path; root_.reset(CreateNewNode(string(name), &type_, LIST, DataPiece::NullData(), false, path, suppress_empty_list_, - preserve_proto_field_names_, + preserve_proto_field_names_, use_ints_for_enums_, field_scrub_callback_.get())); current_ = root_.get(); return this; @@ -570,7 +573,7 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::StartList( google::protobuf::scoped_ptr node( CreateNewNode(string(name), NULL, LIST, DataPiece::NullData(), false, child == NULL ? current_->path() : child->path(), - suppress_empty_list_, preserve_proto_field_names_, + suppress_empty_list_, preserve_proto_field_names_, use_ints_for_enums_, field_scrub_callback_.get())); child = node.get(); current_->AddChild(node.release()); @@ -632,7 +635,7 @@ void DefaultValueObjectWriter::RenderDataPiece(StringPiece name, google::protobuf::scoped_ptr node( CreateNewNode(string(name), NULL, PRIMITIVE, data, false, child == NULL ? current_->path() : child->path(), - suppress_empty_list_, preserve_proto_field_names_, + suppress_empty_list_, preserve_proto_field_names_, use_ints_for_enums_, field_scrub_callback_.get())); current_->AddChild(node.release()); } else { diff --git a/src/google/protobuf/util/internal/default_value_objectwriter.h b/src/google/protobuf/util/internal/default_value_objectwriter.h index 09c6d23f..59f508cd 100644 --- a/src/google/protobuf/util/internal/default_value_objectwriter.h +++ b/src/google/protobuf/util/internal/default_value_objectwriter.h @@ -131,6 +131,12 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { preserve_proto_field_names_ = value; } + // If set to true, enums are rendered as ints from output when default values + // are written. + void set_print_enums_as_ints(bool value) { + use_ints_for_enums_ = value; + } + protected: enum NodeKind { PRIMITIVE = 0, @@ -150,7 +156,7 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { Node(const string& name, const google::protobuf::Type* type, NodeKind kind, const DataPiece& data, bool is_placeholder, const std::vector& path, bool suppress_empty_list, - bool preserve_proto_field_names, + bool preserve_proto_field_names, bool use_ints_for_enums, FieldScrubCallBack* field_scrub_callback); virtual ~Node() { for (int i = 0; i < children_.size(); ++i) { @@ -233,6 +239,9 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { // Whether to preserve original proto field names bool preserve_proto_field_names_; + // Whether to always print enums as ints + bool use_ints_for_enums_; + // Pointer to function for determining whether a field needs to be scrubbed // or not. This callback is owned by the creator of this node. FieldScrubCallBack* field_scrub_callback_; @@ -256,11 +265,12 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { const std::vector& path, bool suppress_empty_list, bool preserve_proto_field_names, + bool use_ints_for_enums, FieldScrubCallBack* field_scrub_callback); // Creates a DataPiece containing the default value of the type of the field. static DataPiece CreateDefaultDataPieceForField( - const google::protobuf::Field& field, const TypeInfo* typeinfo); + const google::protobuf::Field& field, const TypeInfo* typeinfo, bool use_ints_for_enums); protected: // Returns a pointer to current Node in tree. @@ -282,7 +292,8 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { // there is no default. For proto3, where we cannot specify an explicit // default, a zero value will always be returned. static DataPiece FindEnumDefault(const google::protobuf::Field& field, - const TypeInfo* typeinfo); + const TypeInfo* typeinfo, + bool use_ints_for_enums); // Type information for all the types used in the descriptor. Used to find // google::protobuf::Type of nested messages/enums. @@ -307,6 +318,9 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { // Whether to preserve original proto field names bool preserve_proto_field_names_; + // Whether to always print enums as ints + bool use_ints_for_enums_; + // Unique Pointer to function for determining whether a field needs to be // scrubbed or not. FieldScrubCallBackPtr field_scrub_callback_; diff --git a/src/google/protobuf/util/json_format_proto3.proto b/src/google/protobuf/util/json_format_proto3.proto index 8a0441c8..cbc3f81f 100644 --- a/src/google/protobuf/util/json_format_proto3.proto +++ b/src/google/protobuf/util/json_format_proto3.proto @@ -181,3 +181,9 @@ message TestCustomJsonName { message TestExtensions { .protobuf_unittest.TestAllExtensions extensions = 1; } + +message TestEnumValue{ + EnumType enum_value1 = 1; + EnumType enum_value2 = 2; + EnumType enum_value3 = 3; +} \ No newline at end of file diff --git a/src/google/protobuf/util/json_util.cc b/src/google/protobuf/util/json_util.cc index 25e78a65..7221470d 100644 --- a/src/google/protobuf/util/json_util.cc +++ b/src/google/protobuf/util/json_util.cc @@ -97,6 +97,8 @@ util::Status BinaryToJsonStream(TypeResolver* resolver, resolver, type, &json_writer); default_value_writer.set_preserve_proto_field_names( options.preserve_proto_field_names); + default_value_writer.set_print_enums_as_ints( + options.always_print_enums_as_ints); return proto_source.WriteTo(&default_value_writer); } else { return proto_source.WriteTo(&json_writer); diff --git a/src/google/protobuf/util/json_util_test.cc b/src/google/protobuf/util/json_util_test.cc index 3a43ca1c..c3f820a2 100644 --- a/src/google/protobuf/util/json_util_test.cc +++ b/src/google/protobuf/util/json_util_test.cc @@ -54,6 +54,7 @@ using proto3::TestMessage; using proto3::TestMap; using proto3::TestOneof; using google::protobuf::testing::MapIn; +using proto3::TestEnumValue; static const char kTypeUrlPrefix[] = "type.googleapis.com"; @@ -217,6 +218,29 @@ TEST_F(JsonUtilTest, TestAlwaysPrintEnumsAsInts) { EXPECT_EQ(proto3::BAR, parsed.repeated_enum_value(1)); } +TEST_F(JsonUtilTest, TestPrintEnumsAsIntsWithDefaultValue) { + TestEnumValue orig; + //orig.set_enum_value1(proto3::FOO) + orig.set_enum_value2(proto3::FOO); + orig.set_enum_value3(proto3::BAR); + + JsonPrintOptions print_options; + print_options.always_print_enums_as_ints = true; + print_options.always_print_primitive_fields = true; + + string expected_json = "{\"enumValue1\":0,\"enumValue2\":0,\"enumValue3\":1}"; + EXPECT_EQ(expected_json, ToJson(orig, print_options)); + + TestEnumValue parsed; + JsonParseOptions parse_options; + ASSERT_TRUE(FromJson(expected_json, &parsed, parse_options)); + + EXPECT_EQ(proto3::FOO, parsed.enum_value1()); + EXPECT_EQ(proto3::FOO, parsed.enum_value2()); + EXPECT_EQ(proto3::BAR, parsed.enum_value3()); + +} + TEST_F(JsonUtilTest, ParseMessage) { // Some random message but good enough to verify that the parsing warpper // functions are working properly. -- cgit v1.2.3 From d053271deebe0efcd41729991b1f3d618b638ad5 Mon Sep 17 00:00:00 2001 From: stone4774 Date: Wed, 21 Mar 2018 12:25:59 +0800 Subject: Use the first enum value instead of 0 in DefaultValueObjectWriter::FindEnumDefault --- src/google/protobuf/util/internal/default_value_objectwriter.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/google/protobuf/util/internal/default_value_objectwriter.cc b/src/google/protobuf/util/internal/default_value_objectwriter.cc index 32e2429b..032cc700 100644 --- a/src/google/protobuf/util/internal/default_value_objectwriter.cc +++ b/src/google/protobuf/util/internal/default_value_objectwriter.cc @@ -451,7 +451,7 @@ DataPiece DefaultValueObjectWriter::FindEnumDefault( } // We treat the first value as the default if none is specified. return enum_type->enumvalue_size() > 0 - ? (use_ints_for_enums ? DataPiece(0) : DataPiece(enum_type->enumvalue(0).name(), true)) + ? (use_ints_for_enums ? DataPiece(enum_type->enumvalue(0).number()) : DataPiece(enum_type->enumvalue(0).name(), true)) : DataPiece::NullData(); } -- cgit v1.2.3