Index: third_party/protobuf/src/google/protobuf/util/internal/default_value_objectwriter.cc |
diff --git a/third_party/protobuf/src/google/protobuf/util/internal/default_value_objectwriter.cc b/third_party/protobuf/src/google/protobuf/util/internal/default_value_objectwriter.cc |
index 21d7a2e4ab94da0b4e813f814511250ca440cbd2..1772219ab2a9f5f9c71e2c0c9551c866c015f505 100644 |
--- a/third_party/protobuf/src/google/protobuf/util/internal/default_value_objectwriter.cc |
+++ b/third_party/protobuf/src/google/protobuf/util/internal/default_value_objectwriter.cc |
@@ -64,6 +64,7 @@ DefaultValueObjectWriter::DefaultValueObjectWriter( |
type_(type), |
current_(NULL), |
root_(NULL), |
+ suppress_empty_list_(false), |
field_scrub_callback_(NULL), |
ow_(ow) {} |
@@ -164,7 +165,10 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::RenderBytes( |
if (current_ == NULL) { |
ow_->RenderBytes(name, value); |
} else { |
- RenderDataPiece(name, DataPiece(value, false, true)); |
+ // 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; |
} |
@@ -184,12 +188,10 @@ void DefaultValueObjectWriter::RegisterFieldScrubCallBack( |
field_scrub_callback_.reset(field_scrub_callback.release()); |
} |
-DefaultValueObjectWriter::Node::Node(const string& name, |
- const google::protobuf::Type* type, |
- NodeKind kind, const DataPiece& data, |
- bool is_placeholder, |
- const vector<string>& path, |
- FieldScrubCallBack* 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), |
@@ -197,6 +199,7 @@ DefaultValueObjectWriter::Node::Node(const string& name, |
data_(data), |
is_placeholder_(is_placeholder), |
path_(path), |
+ suppress_empty_list_(suppress_empty_list), |
field_scrub_callback_(field_scrub_callback) {} |
DefaultValueObjectWriter::Node* DefaultValueObjectWriter::Node::FindChild( |
@@ -230,6 +233,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(); |
@@ -304,7 +310,7 @@ void DefaultValueObjectWriter::Node::PopulateChildren( |
// 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. |
- vector<string> path; |
+ std::vector<string> path; |
if (!path_.empty()) { |
path.insert(path.begin(), path_.begin(), path_.end()); |
} |
@@ -366,7 +372,7 @@ void DefaultValueObjectWriter::Node::PopulateChildren( |
field.json_name(), field_type, kind, |
kind == PRIMITIVE ? CreateDefaultDataPieceForField(field, typeinfo) |
: DataPiece::NullData(), |
- true, path, field_scrub_callback_)); |
+ true, path, suppress_empty_list_, field_scrub_callback_)); |
new_children.push_back(child.release()); |
} |
// Adds all leftover nodes in children_ to the beginning of new_child. |
@@ -460,9 +466,10 @@ DataPiece DefaultValueObjectWriter::CreateDefaultDataPieceForField( |
DefaultValueObjectWriter* DefaultValueObjectWriter::StartObject( |
StringPiece name) { |
if (current_ == NULL) { |
- vector<string> path; |
+ std::vector<string> path; |
root_.reset(new Node(name.ToString(), &type_, OBJECT, DataPiece::NullData(), |
- false, path, field_scrub_callback_.get())); |
+ false, path, suppress_empty_list_, |
+ field_scrub_callback_.get())); |
root_->PopulateChildren(typeinfo_); |
current_ = root_.get(); |
return this; |
@@ -478,7 +485,7 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::StartObject( |
: NULL), |
OBJECT, DataPiece::NullData(), false, |
child == NULL ? current_->path() : child->path(), |
- field_scrub_callback_.get())); |
+ suppress_empty_list_, field_scrub_callback_.get())); |
child = node.get(); |
current_->AddChild(node.release()); |
} |
@@ -507,9 +514,10 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::EndObject() { |
DefaultValueObjectWriter* DefaultValueObjectWriter::StartList( |
StringPiece name) { |
if (current_ == NULL) { |
- vector<string> path; |
+ std::vector<string> path; |
root_.reset(new Node(name.ToString(), &type_, LIST, DataPiece::NullData(), |
- false, path, field_scrub_callback_.get())); |
+ false, path, suppress_empty_list_, |
+ field_scrub_callback_.get())); |
current_ = root_.get(); |
return this; |
} |
@@ -519,7 +527,7 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::StartList( |
google::protobuf::scoped_ptr<Node> node( |
new Node(name.ToString(), NULL, LIST, DataPiece::NullData(), false, |
child == NULL ? current_->path() : child->path(), |
- field_scrub_callback_.get())); |
+ suppress_empty_list_, field_scrub_callback_.get())); |
child = node.get(); |
current_->AddChild(node.release()); |
} |
@@ -549,26 +557,29 @@ 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_); |
+ 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() != NULL) { |
+ current_->PopulateChildren(typeinfo_); |
+ } |
} |
} |
Node* child = current_->FindChild(name); |
@@ -577,8 +588,7 @@ void DefaultValueObjectWriter::RenderDataPiece(StringPiece name, |
google::protobuf::scoped_ptr<Node> node( |
new Node(name.ToString(), NULL, PRIMITIVE, data, false, |
child == NULL ? current_->path() : child->path(), |
- field_scrub_callback_.get())); |
- child = node.get(); |
+ suppress_empty_list_, field_scrub_callback_.get())); |
current_->AddChild(node.release()); |
} else { |
child->set_data(data); |