diff options
Diffstat (limited to 'src/google/protobuf/util/internal/default_value_objectwriter.cc')
-rw-r--r-- | src/google/protobuf/util/internal/default_value_objectwriter.cc | 257 |
1 files changed, 174 insertions, 83 deletions
diff --git a/src/google/protobuf/util/internal/default_value_objectwriter.cc b/src/google/protobuf/util/internal/default_value_objectwriter.cc index a63e560d..b41feb7a 100644 --- a/src/google/protobuf/util/internal/default_value_objectwriter.cc +++ b/src/google/protobuf/util/internal/default_value_objectwriter.cc @@ -51,7 +51,7 @@ template <typename T> T ConvertTo(StringPiece value, StatusOr<T> (DataPiece::*converter_fn)() const, T default_value) { if (value.empty()) return default_value; - StatusOr<T> result = (DataPiece(value).*converter_fn)(); + StatusOr<T> result = (DataPiece(value, true).*converter_fn)(); return result.ok() ? result.ValueOrDie() : default_value; } } // namespace @@ -62,8 +62,12 @@ DefaultValueObjectWriter::DefaultValueObjectWriter( : typeinfo_(TypeInfo::NewTypeInfo(type_resolver)), own_typeinfo_(true), type_(type), - current_(NULL), - root_(NULL), + current_(nullptr), + root_(nullptr), + suppress_empty_list_(false), + preserve_proto_field_names_(false), + use_ints_for_enums_(false), + field_scrub_callback_(nullptr), ow_(ow) {} DefaultValueObjectWriter::~DefaultValueObjectWriter() { @@ -77,7 +81,7 @@ DefaultValueObjectWriter::~DefaultValueObjectWriter() { DefaultValueObjectWriter* DefaultValueObjectWriter::RenderBool(StringPiece name, bool value) { - if (current_ == NULL) { + if (current_ == nullptr) { ow_->RenderBool(name, value); } else { RenderDataPiece(name, DataPiece(value)); @@ -87,7 +91,7 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::RenderBool(StringPiece name, DefaultValueObjectWriter* DefaultValueObjectWriter::RenderInt32( StringPiece name, int32 value) { - if (current_ == NULL) { + if (current_ == nullptr) { ow_->RenderInt32(name, value); } else { RenderDataPiece(name, DataPiece(value)); @@ -97,7 +101,7 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::RenderInt32( DefaultValueObjectWriter* DefaultValueObjectWriter::RenderUint32( StringPiece name, uint32 value) { - if (current_ == NULL) { + if (current_ == nullptr) { ow_->RenderUint32(name, value); } else { RenderDataPiece(name, DataPiece(value)); @@ -107,7 +111,7 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::RenderUint32( DefaultValueObjectWriter* DefaultValueObjectWriter::RenderInt64( StringPiece name, int64 value) { - if (current_ == NULL) { + if (current_ == nullptr) { ow_->RenderInt64(name, value); } else { RenderDataPiece(name, DataPiece(value)); @@ -117,7 +121,7 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::RenderInt64( DefaultValueObjectWriter* DefaultValueObjectWriter::RenderUint64( StringPiece name, uint64 value) { - if (current_ == NULL) { + if (current_ == nullptr) { ow_->RenderUint64(name, value); } else { RenderDataPiece(name, DataPiece(value)); @@ -127,7 +131,7 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::RenderUint64( DefaultValueObjectWriter* DefaultValueObjectWriter::RenderDouble( StringPiece name, double value) { - if (current_ == NULL) { + if (current_ == nullptr) { ow_->RenderDouble(name, value); } else { RenderDataPiece(name, DataPiece(value)); @@ -137,7 +141,7 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::RenderDouble( DefaultValueObjectWriter* DefaultValueObjectWriter::RenderFloat( StringPiece name, float value) { - if (current_ == NULL) { + if (current_ == nullptr) { ow_->RenderBool(name, value); } else { RenderDataPiece(name, DataPiece(value)); @@ -147,30 +151,33 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::RenderFloat( DefaultValueObjectWriter* DefaultValueObjectWriter::RenderString( StringPiece name, StringPiece value) { - if (current_ == NULL) { + if (current_ == nullptr) { ow_->RenderString(name, value); } else { // Since StringPiece is essentially a pointer, takes a copy of "value" to // avoid ownership issues. string_values_.push_back(new string(value.ToString())); - RenderDataPiece(name, DataPiece(*string_values_.back())); + RenderDataPiece(name, DataPiece(*string_values_.back(), true)); } return this; } DefaultValueObjectWriter* DefaultValueObjectWriter::RenderBytes( StringPiece name, StringPiece value) { - if (current_ == NULL) { + if (current_ == nullptr) { ow_->RenderBytes(name, value); } else { - RenderDataPiece(name, DataPiece(value)); + // Since StringPiece is essentially a pointer, takes a copy of "value" to + // avoid ownership issues. + string_values_.push_back(new string(value.ToString())); + RenderDataPiece(name, DataPiece(*string_values_.back(), false, true)); } return this; } DefaultValueObjectWriter* DefaultValueObjectWriter::RenderNull( StringPiece name) { - if (current_ == NULL) { + if (current_ == nullptr) { ow_->RenderNull(name); } else { RenderDataPiece(name, DataPiece::NullData()); @@ -178,21 +185,66 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::RenderNull( return this; } -DefaultValueObjectWriter::Node::Node(const string& name, - const google::protobuf::Type* type, - NodeKind kind, const DataPiece& data, - bool is_placeholder) +void DefaultValueObjectWriter::RegisterFieldScrubCallBack( + FieldScrubCallBackPtr field_scrub_callback) { + field_scrub_callback_.reset(field_scrub_callback.release()); +} + +DefaultValueObjectWriter::Node* DefaultValueObjectWriter::CreateNewNode( + const string& name, const google::protobuf::Type* type, NodeKind kind, + const DataPiece& data, bool is_placeholder, const std::vector<string>& path, + bool suppress_empty_list, FieldScrubCallBack* field_scrub_callback) { + return new Node(name, type, kind, data, is_placeholder, path, + suppress_empty_list, field_scrub_callback); +} + +DefaultValueObjectWriter::Node* DefaultValueObjectWriter::CreateNewNode( + const string& name, const google::protobuf::Type* type, NodeKind kind, + const DataPiece& data, bool is_placeholder, const std::vector<string>& path, + 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, use_ints_for_enums, + 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<string>& path, + bool suppress_empty_list, FieldScrubCallBack* field_scrub_callback) : name_(name), type_(type), kind_(kind), is_any_(false), data_(data), - is_placeholder_(is_placeholder) {} + is_placeholder_(is_placeholder), + 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<string>& path, + bool suppress_empty_list, bool preserve_proto_field_names, bool use_ints_for_enums, + FieldScrubCallBack* field_scrub_callback) + : name_(name), + type_(type), + kind_(kind), + is_any_(false), + data_(data), + is_placeholder_(is_placeholder), + 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( StringPiece name) { if (name.empty() || kind_ != OBJECT) { - return NULL; + return nullptr; } for (int i = 0; i < children_.size(); ++i) { Node* child = children_[i]; @@ -200,7 +252,7 @@ DefaultValueObjectWriter::Node* DefaultValueObjectWriter::Node::FindChild( return child; } } - return NULL; + return nullptr; } void DefaultValueObjectWriter::Node::WriteTo(ObjectWriter* ow) { @@ -220,6 +272,9 @@ void DefaultValueObjectWriter::Node::WriteTo(ObjectWriter* ow) { // Write out lists. If we didn't have any list in response, write out empty // list. if (kind_ == LIST) { + // Suppress empty lists if requested. + if (suppress_empty_list_ && is_placeholder_) return; + ow->StartList(name_); WriteChildren(ow); ow->EndList(); @@ -265,7 +320,7 @@ const google::protobuf::Type* DefaultValueObjectWriter::Node::GetMapValueType( } break; } - return NULL; + return nullptr; } void DefaultValueObjectWriter::Node::PopulateChildren( @@ -276,7 +331,7 @@ void DefaultValueObjectWriter::Node::PopulateChildren( // TODO(tsun): remove "kStructValueType" from the list. It's being checked // now because of a bug in the tool-chain that causes the "oneof_index" // of kStructValueType to not be set correctly. - if (type_ == NULL || type_->name() == kAnyType || + if (type_ == nullptr || type_->name() == kAnyType || type_->name() == kStructType || type_->name() == kTimestampType || type_->name() == kDurationType || type_->name() == kStructValueType) { return; @@ -291,17 +346,30 @@ void DefaultValueObjectWriter::Node::PopulateChildren( for (int i = 0; i < type_->fields_size(); ++i) { const google::protobuf::Field& field = type_->fields(i); + + // This code is checking if the field to be added to the tree should be + // scrubbed or not by calling the field_scrub_callback_ callback function. + std::vector<string> path; + if (!path_.empty()) { + path.insert(path.begin(), path_.begin(), path_.end()); + } + path.push_back(field.name()); + if (field_scrub_callback_ != nullptr && + field_scrub_callback_->Run(path, &field)) { + continue; + } + hash_map<string, int>::iterator found = orig_children_map.find(field.name()); // If the child field has already been set, we just add it to the new list // of children. if (found != orig_children_map.end()) { new_children.push_back(children_[found->second]); - children_[found->second] = NULL; + children_[found->second] = nullptr; continue; } - const google::protobuf::Type* field_type = NULL; + const google::protobuf::Type* field_type = nullptr; bool is_map = false; NodeKind kind = PRIMITIVE; @@ -334,25 +402,28 @@ void DefaultValueObjectWriter::Node::PopulateChildren( } // If oneof_index() != 0, the child field is part of a "oneof", which means - // the child field is optional and we shouldn't populate its default value. - if (field.oneof_index() != 0) continue; + // the child field is optional and we shouldn't populate its default + // primitive value. + if (field.oneof_index() != 0 && kind == PRIMITIVE) continue; // If the child field is of primitive type, sets its data to the default // value of its type. - google::protobuf::scoped_ptr<Node> child(new Node( - field.json_name(), field_type, kind, - kind == PRIMITIVE ? CreateDefaultDataPieceForField(field, typeinfo) + std::unique_ptr<Node> child(new Node( + preserve_proto_field_names_ ? field.name() : field.json_name(), + field_type, kind, + kind == PRIMITIVE ? CreateDefaultDataPieceForField(field, typeinfo, use_ints_for_enums_) : DataPiece::NullData(), - true)); + true, path, suppress_empty_list_, preserve_proto_field_names_, use_ints_for_enums_, + field_scrub_callback_)); new_children.push_back(child.release()); } // Adds all leftover nodes in children_ to the beginning of new_child. for (int i = 0; i < children_.size(); ++i) { - if (children_[i] == NULL) { + if (children_[i] == nullptr) { continue; } new_children.insert(new_children.begin(), children_[i]); - children_[i] = NULL; + children_[i] = nullptr; } children_.swap(new_children); } @@ -360,15 +431,16 @@ void DefaultValueObjectWriter::Node::PopulateChildren( void DefaultValueObjectWriter::MaybePopulateChildrenOfAny(Node* node) { // If this is an "Any" node with "@type" already given and no other children // have been added, populates its children. - if (node != NULL && node->is_any() && node->type() != NULL && + if (node != nullptr && node->is_any() && node->type() != nullptr && node->type()->name() != kAnyType && node->number_of_children() == 1) { node->PopulateChildren(typeinfo_); } } DataPiece DefaultValueObjectWriter::FindEnumDefault( - const google::protobuf::Field& field, const TypeInfo* typeinfo) { - if (!field.default_value().empty()) return DataPiece(field.default_value()); + const google::protobuf::Field& field, const TypeInfo* typeinfo, bool use_ints_for_enums) { + if (!field.default_value().empty()) + return DataPiece(field.default_value(), true); const google::protobuf::Enum* enum_type = typeinfo->GetEnumByTypeUrl(field.type_url()); @@ -379,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()) + ? (use_ints_for_enums ? DataPiece(enum_type->enumvalue(0).number()) : 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<double>( @@ -416,10 +488,10 @@ DataPiece DefaultValueObjectWriter::CreateDefaultDataPieceForField( ConvertTo<bool>(field.default_value(), &DataPiece::ToBool, false)); } case google::protobuf::Field_Kind_TYPE_STRING: { - return DataPiece(field.default_value()); + return DataPiece(field.default_value(), true); } case google::protobuf::Field_Kind_TYPE_BYTES: { - return DataPiece(field.default_value(), false); + return DataPiece(field.default_value(), false, true); } case google::protobuf::Field_Kind_TYPE_UINT32: case google::protobuf::Field_Kind_TYPE_FIXED32: { @@ -427,7 +499,7 @@ DataPiece DefaultValueObjectWriter::CreateDefaultDataPieceForField( field.default_value(), &DataPiece::ToUint32, static_cast<uint32>(0))); } case google::protobuf::Field_Kind_TYPE_ENUM: { - return FindEnumDefault(field, typeinfo); + return FindEnumDefault(field, typeinfo, use_ints_for_enums); } default: { return DataPiece::NullData(); } } @@ -435,23 +507,30 @@ DataPiece DefaultValueObjectWriter::CreateDefaultDataPieceForField( DefaultValueObjectWriter* DefaultValueObjectWriter::StartObject( StringPiece name) { - if (current_ == NULL) { - root_.reset(new Node(name.ToString(), &type_, OBJECT, DataPiece::NullData(), - false)); + if (current_ == nullptr) { + std::vector<string> path; + root_.reset(CreateNewNode(string(name), &type_, OBJECT, + DataPiece::NullData(), false, path, + suppress_empty_list_, preserve_proto_field_names_, use_ints_for_enums_, + field_scrub_callback_.get())); root_->PopulateChildren(typeinfo_); current_ = root_.get(); return this; } MaybePopulateChildrenOfAny(current_); Node* child = current_->FindChild(name); - if (current_->kind() == LIST || current_->kind() == MAP || child == NULL) { + if (current_->kind() == LIST || current_->kind() == MAP || child == nullptr) { // If current_ is a list or a map node, we should create a new child and use // the type of current_ as the type of the new child. - google::protobuf::scoped_ptr<Node> node(new Node( - name.ToString(), ((current_->kind() == LIST || current_->kind() == MAP) - ? current_->type() - : NULL), - OBJECT, DataPiece::NullData(), false)); + std::unique_ptr<Node> node( + CreateNewNode(string(name), + ((current_->kind() == LIST || current_->kind() == MAP) + ? current_->type() + : nullptr), + OBJECT, DataPiece::NullData(), false, + child == nullptr ? current_->path() : child->path(), + suppress_empty_list_, preserve_proto_field_names_, use_ints_for_enums_, + field_scrub_callback_.get())); child = node.get(); current_->AddChild(node.release()); } @@ -479,17 +558,23 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::EndObject() { DefaultValueObjectWriter* DefaultValueObjectWriter::StartList( StringPiece name) { - if (current_ == NULL) { - root_.reset( - new Node(name.ToString(), &type_, LIST, DataPiece::NullData(), false)); + if (current_ == nullptr) { + std::vector<string> path; + root_.reset(CreateNewNode(string(name), &type_, LIST, DataPiece::NullData(), + false, path, suppress_empty_list_, + preserve_proto_field_names_, use_ints_for_enums_, + field_scrub_callback_.get())); current_ = root_.get(); return this; } MaybePopulateChildrenOfAny(current_); Node* child = current_->FindChild(name); - if (child == NULL || child->kind() != LIST) { - google::protobuf::scoped_ptr<Node> node( - new Node(name.ToString(), NULL, LIST, DataPiece::NullData(), false)); + if (child == nullptr || child->kind() != LIST) { + std::unique_ptr<Node> node( + CreateNewNode(string(name), nullptr, LIST, DataPiece::NullData(), false, + child == nullptr ? current_->path() : child->path(), + suppress_empty_list_, preserve_proto_field_names_, use_ints_for_enums_, + field_scrub_callback_.get())); child = node.get(); current_->AddChild(node.release()); } @@ -502,8 +587,8 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::StartList( void DefaultValueObjectWriter::WriteRoot() { root_->WriteTo(ow_); - root_.reset(NULL); - current_ = NULL; + root_.reset(nullptr); + current_ = nullptr; } DefaultValueObjectWriter* DefaultValueObjectWriter::EndList() { @@ -519,37 +604,43 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::EndList() { void DefaultValueObjectWriter::RenderDataPiece(StringPiece name, const DataPiece& data) { MaybePopulateChildrenOfAny(current_); - util::StatusOr<string> data_string = data.ToString(); - if (current_->type() != NULL && current_->type()->name() == kAnyType && - name == "@type" && data_string.ok()) { - const string& string_value = data_string.ValueOrDie(); - // If the type of current_ is "Any" and its "@type" field is being set here, - // sets the type of current_ to be the type specified by the "@type". - util::StatusOr<const google::protobuf::Type*> found_type = - typeinfo_->ResolveTypeUrl(string_value); - if (!found_type.ok()) { - GOOGLE_LOG(WARNING) << "Failed to resolve type '" << string_value << "'."; - } else { - current_->set_type(found_type.ValueOrDie()); - } - current_->set_is_any(true); - // If the "@type" field is placed after other fields, we should populate - // other children of primitive type now. Otherwise, we should wait until the - // first value field is rendered before we populate the children, because - // the "value" field of a Any message could be omitted. - if (current_->number_of_children() > 1 && current_->type() != NULL) { - current_->PopulateChildren(typeinfo_); + if (current_->type() != nullptr && current_->type()->name() == kAnyType && + name == "@type") { + util::StatusOr<string> data_string = data.ToString(); + if (data_string.ok()) { + const string& string_value = data_string.ValueOrDie(); + // If the type of current_ is "Any" and its "@type" field is being set + // here, sets the type of current_ to be the type specified by the + // "@type". + util::StatusOr<const google::protobuf::Type*> found_type = + typeinfo_->ResolveTypeUrl(string_value); + if (!found_type.ok()) { + GOOGLE_LOG(WARNING) << "Failed to resolve type '" << string_value << "'."; + } else { + current_->set_type(found_type.ValueOrDie()); + } + current_->set_is_any(true); + // If the "@type" field is placed after other fields, we should populate + // other children of primitive type now. Otherwise, we should wait until + // the first value field is rendered before we populate the children, + // because the "value" field of a Any message could be omitted. + if (current_->number_of_children() > 1 && current_->type() != nullptr) { + current_->PopulateChildren(typeinfo_); + } } } Node* child = current_->FindChild(name); - if (child == NULL || child->kind() != PRIMITIVE) { + if (child == nullptr || child->kind() != PRIMITIVE) { // No children are found, creates a new child. - google::protobuf::scoped_ptr<Node> node( - new Node(name.ToString(), NULL, PRIMITIVE, data, false)); - child = node.get(); + std::unique_ptr<Node> node( + CreateNewNode(string(name), nullptr, PRIMITIVE, data, false, + child == nullptr ? current_->path() : child->path(), + suppress_empty_list_, preserve_proto_field_names_, use_ints_for_enums_, + field_scrub_callback_.get())); current_->AddChild(node.release()); } else { child->set_data(data); + child->set_is_placeholder(false); } } |