1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 // * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 // * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31 #include <google/protobuf/util/internal/default_value_objectwriter.h>
32
33 #include <unordered_map>
34
35 #include <google/protobuf/util/internal/constants.h>
36 #include <google/protobuf/util/internal/utility.h>
37 #include <google/protobuf/stubs/map_util.h>
38
39 namespace google {
40 namespace protobuf {
41 namespace util {
42 using util::Status;
43 using util::StatusOr;
44 namespace converter {
45
46 namespace {
47 // Helper function to convert string value to given data type by calling the
48 // passed converter function on the DataPiece created from "value" argument.
49 // If value is empty or if conversion fails, the default_value is returned.
50 template <typename T>
ConvertTo(StringPiece value,StatusOr<T> (DataPiece::* converter_fn)()const,T default_value)51 T ConvertTo(StringPiece value,
52 StatusOr<T> (DataPiece::*converter_fn)() const, T default_value) {
53 if (value.empty()) return default_value;
54 StatusOr<T> result = (DataPiece(value, true).*converter_fn)();
55 return result.ok() ? result.ValueOrDie() : default_value;
56 }
57 } // namespace
58
DefaultValueObjectWriter(TypeResolver * type_resolver,const google::protobuf::Type & type,ObjectWriter * ow)59 DefaultValueObjectWriter::DefaultValueObjectWriter(
60 TypeResolver* type_resolver, const google::protobuf::Type& type,
61 ObjectWriter* ow)
62 : typeinfo_(TypeInfo::NewTypeInfo(type_resolver)),
63 own_typeinfo_(true),
64 type_(type),
65 current_(nullptr),
66 root_(nullptr),
67 suppress_empty_list_(false),
68 preserve_proto_field_names_(false),
69 use_ints_for_enums_(false),
70 field_scrub_callback_(nullptr),
71 ow_(ow) {}
72
~DefaultValueObjectWriter()73 DefaultValueObjectWriter::~DefaultValueObjectWriter() {
74 if (own_typeinfo_) {
75 delete typeinfo_;
76 }
77 }
78
RenderBool(StringPiece name,bool value)79 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderBool(
80 StringPiece name, bool value) {
81 if (current_ == nullptr) {
82 ow_->RenderBool(name, value);
83 } else {
84 RenderDataPiece(name, DataPiece(value));
85 }
86 return this;
87 }
88
RenderInt32(StringPiece name,int32 value)89 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderInt32(
90 StringPiece name, int32 value) {
91 if (current_ == nullptr) {
92 ow_->RenderInt32(name, value);
93 } else {
94 RenderDataPiece(name, DataPiece(value));
95 }
96 return this;
97 }
98
RenderUint32(StringPiece name,uint32 value)99 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderUint32(
100 StringPiece name, uint32 value) {
101 if (current_ == nullptr) {
102 ow_->RenderUint32(name, value);
103 } else {
104 RenderDataPiece(name, DataPiece(value));
105 }
106 return this;
107 }
108
RenderInt64(StringPiece name,int64 value)109 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderInt64(
110 StringPiece name, int64 value) {
111 if (current_ == nullptr) {
112 ow_->RenderInt64(name, value);
113 } else {
114 RenderDataPiece(name, DataPiece(value));
115 }
116 return this;
117 }
118
RenderUint64(StringPiece name,uint64 value)119 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderUint64(
120 StringPiece name, uint64 value) {
121 if (current_ == nullptr) {
122 ow_->RenderUint64(name, value);
123 } else {
124 RenderDataPiece(name, DataPiece(value));
125 }
126 return this;
127 }
128
RenderDouble(StringPiece name,double value)129 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderDouble(
130 StringPiece name, double value) {
131 if (current_ == nullptr) {
132 ow_->RenderDouble(name, value);
133 } else {
134 RenderDataPiece(name, DataPiece(value));
135 }
136 return this;
137 }
138
RenderFloat(StringPiece name,float value)139 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderFloat(
140 StringPiece name, float value) {
141 if (current_ == nullptr) {
142 ow_->RenderBool(name, value);
143 } else {
144 RenderDataPiece(name, DataPiece(value));
145 }
146 return this;
147 }
148
RenderString(StringPiece name,StringPiece value)149 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderString(
150 StringPiece name, StringPiece value) {
151 if (current_ == nullptr) {
152 ow_->RenderString(name, value);
153 } else {
154 // Since StringPiece is essentially a pointer, takes a copy of "value" to
155 // avoid ownership issues.
156 string_values_.emplace_back(new std::string(value));
157 RenderDataPiece(name, DataPiece(*string_values_.back(), true));
158 }
159 return this;
160 }
161
RenderBytes(StringPiece name,StringPiece value)162 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderBytes(
163 StringPiece name, StringPiece value) {
164 if (current_ == nullptr) {
165 ow_->RenderBytes(name, value);
166 } else {
167 // Since StringPiece is essentially a pointer, takes a copy of "value" to
168 // avoid ownership issues.
169 string_values_.emplace_back(new std::string(value));
170 RenderDataPiece(name, DataPiece(*string_values_.back(), false, true));
171 }
172 return this;
173 }
174
RenderNull(StringPiece name)175 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderNull(
176 StringPiece name) {
177 if (current_ == nullptr) {
178 ow_->RenderNull(name);
179 } else {
180 RenderDataPiece(name, DataPiece::NullData());
181 }
182 return this;
183 }
184
RegisterFieldScrubCallBack(FieldScrubCallBackPtr field_scrub_callback)185 void DefaultValueObjectWriter::RegisterFieldScrubCallBack(
186 FieldScrubCallBackPtr field_scrub_callback) {
187 field_scrub_callback_.reset(field_scrub_callback.release());
188 }
189
CreateNewNode(const std::string & name,const google::protobuf::Type * type,NodeKind kind,const DataPiece & data,bool is_placeholder,const std::vector<std::string> & path,bool suppress_empty_list,bool preserve_proto_field_names,bool use_ints_for_enums,FieldScrubCallBack * field_scrub_callback)190 DefaultValueObjectWriter::Node* DefaultValueObjectWriter::CreateNewNode(
191 const std::string& name, const google::protobuf::Type* type, NodeKind kind,
192 const DataPiece& data, bool is_placeholder,
193 const std::vector<std::string>& path, bool suppress_empty_list,
194 bool preserve_proto_field_names, bool use_ints_for_enums,
195 FieldScrubCallBack* field_scrub_callback) {
196 return new Node(name, type, kind, data, is_placeholder, path,
197 suppress_empty_list, preserve_proto_field_names,
198 use_ints_for_enums, field_scrub_callback);
199 }
200
Node(const std::string & name,const google::protobuf::Type * type,NodeKind kind,const DataPiece & data,bool is_placeholder,const std::vector<std::string> & path,bool suppress_empty_list,bool preserve_proto_field_names,bool use_ints_for_enums,FieldScrubCallBack * field_scrub_callback)201 DefaultValueObjectWriter::Node::Node(
202 const std::string& name, const google::protobuf::Type* type, NodeKind kind,
203 const DataPiece& data, bool is_placeholder,
204 const std::vector<std::string>& path, bool suppress_empty_list,
205 bool preserve_proto_field_names, bool use_ints_for_enums,
206 FieldScrubCallBack* field_scrub_callback)
207 : name_(name),
208 type_(type),
209 kind_(kind),
210 is_any_(false),
211 data_(data),
212 is_placeholder_(is_placeholder),
213 path_(path),
214 suppress_empty_list_(suppress_empty_list),
215 preserve_proto_field_names_(preserve_proto_field_names),
216 use_ints_for_enums_(use_ints_for_enums),
217 field_scrub_callback_(field_scrub_callback) {}
218
FindChild(StringPiece name)219 DefaultValueObjectWriter::Node* DefaultValueObjectWriter::Node::FindChild(
220 StringPiece name) {
221 if (name.empty() || kind_ != OBJECT) {
222 return nullptr;
223 }
224 for (int i = 0; i < children_.size(); ++i) {
225 Node* child = children_[i];
226 if (child->name() == name) {
227 return child;
228 }
229 }
230 return nullptr;
231 }
232
WriteTo(ObjectWriter * ow)233 void DefaultValueObjectWriter::Node::WriteTo(ObjectWriter* ow) {
234 if (kind_ == PRIMITIVE) {
235 ObjectWriter::RenderDataPieceTo(data_, name_, ow);
236 return;
237 }
238
239 // Render maps. Empty maps are rendered as "{}".
240 if (kind_ == MAP) {
241 ow->StartObject(name_);
242 WriteChildren(ow);
243 ow->EndObject();
244 return;
245 }
246
247 // Write out lists. If we didn't have any list in response, write out empty
248 // list.
249 if (kind_ == LIST) {
250 // Suppress empty lists if requested.
251 if (suppress_empty_list_ && is_placeholder_) return;
252
253 ow->StartList(name_);
254 WriteChildren(ow);
255 ow->EndList();
256 return;
257 }
258
259 // If is_placeholder_ = true, we didn't see this node in the response, so
260 // skip output.
261 if (is_placeholder_) return;
262
263 ow->StartObject(name_);
264 WriteChildren(ow);
265 ow->EndObject();
266 }
267
WriteChildren(ObjectWriter * ow)268 void DefaultValueObjectWriter::Node::WriteChildren(ObjectWriter* ow) {
269 for (int i = 0; i < children_.size(); ++i) {
270 Node* child = children_[i];
271 child->WriteTo(ow);
272 }
273 }
274
GetMapValueType(const google::protobuf::Type & found_type,const TypeInfo * typeinfo)275 const google::protobuf::Type* DefaultValueObjectWriter::Node::GetMapValueType(
276 const google::protobuf::Type& found_type, const TypeInfo* typeinfo) {
277 // If this field is a map, we should use the type of its "Value" as
278 // the type of the child node.
279 for (int i = 0; i < found_type.fields_size(); ++i) {
280 const google::protobuf::Field& sub_field = found_type.fields(i);
281 if (sub_field.number() != 2) {
282 continue;
283 }
284 if (sub_field.kind() != google::protobuf::Field_Kind_TYPE_MESSAGE) {
285 // This map's value type is not a message type. We don't need to
286 // get the field_type in this case.
287 break;
288 }
289 util::StatusOr<const google::protobuf::Type*> sub_type =
290 typeinfo->ResolveTypeUrl(sub_field.type_url());
291 if (!sub_type.ok()) {
292 GOOGLE_LOG(WARNING) << "Cannot resolve type '" << sub_field.type_url() << "'.";
293 } else {
294 return sub_type.ValueOrDie();
295 }
296 break;
297 }
298 return nullptr;
299 }
300
PopulateChildren(const TypeInfo * typeinfo)301 void DefaultValueObjectWriter::Node::PopulateChildren(
302 const TypeInfo* typeinfo) {
303 // Ignores well known types that don't require automatically populating their
304 // primitive children. For type "Any", we only populate its children when the
305 // "@type" field is set.
306 // TODO(tsun): remove "kStructValueType" from the list. It's being checked
307 // now because of a bug in the tool-chain that causes the "oneof_index"
308 // of kStructValueType to not be set correctly.
309 if (type_ == nullptr || type_->name() == kAnyType ||
310 type_->name() == kStructType || type_->name() == kTimestampType ||
311 type_->name() == kDurationType || type_->name() == kStructValueType) {
312 return;
313 }
314 std::vector<Node*> new_children;
315 std::unordered_map<std::string, int> orig_children_map;
316
317 // Creates a map of child nodes to speed up lookup.
318 for (int i = 0; i < children_.size(); ++i) {
319 InsertIfNotPresent(&orig_children_map, children_[i]->name_, i);
320 }
321
322 for (int i = 0; i < type_->fields_size(); ++i) {
323 const google::protobuf::Field& field = type_->fields(i);
324
325 // This code is checking if the field to be added to the tree should be
326 // scrubbed or not by calling the field_scrub_callback_ callback function.
327 std::vector<std::string> path;
328 if (!path_.empty()) {
329 path.insert(path.begin(), path_.begin(), path_.end());
330 }
331 path.push_back(field.name());
332 if (field_scrub_callback_ != nullptr &&
333 field_scrub_callback_->Run(path, &field)) {
334 continue;
335 }
336
337 std::unordered_map<std::string, int>::iterator found =
338 orig_children_map.find(field.name());
339 // If the child field has already been set, we just add it to the new list
340 // of children.
341 if (found != orig_children_map.end()) {
342 new_children.push_back(children_[found->second]);
343 children_[found->second] = nullptr;
344 continue;
345 }
346
347 const google::protobuf::Type* field_type = nullptr;
348 bool is_map = false;
349 NodeKind kind = PRIMITIVE;
350
351 if (field.kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) {
352 kind = OBJECT;
353 util::StatusOr<const google::protobuf::Type*> found_result =
354 typeinfo->ResolveTypeUrl(field.type_url());
355 if (!found_result.ok()) {
356 // "field" is of an unknown type.
357 GOOGLE_LOG(WARNING) << "Cannot resolve type '" << field.type_url() << "'.";
358 } else {
359 const google::protobuf::Type* found_type = found_result.ValueOrDie();
360 is_map = IsMap(field, *found_type);
361
362 if (!is_map) {
363 field_type = found_type;
364 } else {
365 // If this field is a map, we should use the type of its "Value" as
366 // the type of the child node.
367 field_type = GetMapValueType(*found_type, typeinfo);
368 kind = MAP;
369 }
370 }
371 }
372
373 if (!is_map &&
374 field.cardinality() ==
375 google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) {
376 kind = LIST;
377 }
378
379 // If oneof_index() != 0, the child field is part of a "oneof", which means
380 // the child field is optional and we shouldn't populate its default
381 // primitive value.
382 if (field.oneof_index() != 0 && kind == PRIMITIVE) continue;
383
384 // If the child field is of primitive type, sets its data to the default
385 // value of its type.
386 std::unique_ptr<Node> child(
387 new Node(preserve_proto_field_names_ ? field.name() : field.json_name(),
388 field_type, kind,
389 kind == PRIMITIVE ? CreateDefaultDataPieceForField(
390 field, typeinfo, use_ints_for_enums_)
391 : DataPiece::NullData(),
392 true, path, suppress_empty_list_, preserve_proto_field_names_,
393 use_ints_for_enums_, field_scrub_callback_));
394 new_children.push_back(child.release());
395 }
396 // Adds all leftover nodes in children_ to the beginning of new_child.
397 for (int i = 0; i < children_.size(); ++i) {
398 if (children_[i] == nullptr) {
399 continue;
400 }
401 new_children.insert(new_children.begin(), children_[i]);
402 children_[i] = nullptr;
403 }
404 children_.swap(new_children);
405 }
406
MaybePopulateChildrenOfAny(Node * node)407 void DefaultValueObjectWriter::MaybePopulateChildrenOfAny(Node* node) {
408 // If this is an "Any" node with "@type" already given and no other children
409 // have been added, populates its children.
410 if (node != nullptr && node->is_any() && node->type() != nullptr &&
411 node->type()->name() != kAnyType && node->number_of_children() == 1) {
412 node->PopulateChildren(typeinfo_);
413 }
414 }
415
FindEnumDefault(const google::protobuf::Field & field,const TypeInfo * typeinfo,bool use_ints_for_enums)416 DataPiece DefaultValueObjectWriter::FindEnumDefault(
417 const google::protobuf::Field& field, const TypeInfo* typeinfo,
418 bool use_ints_for_enums) {
419 if (!field.default_value().empty())
420 return DataPiece(field.default_value(), true);
421
422 const google::protobuf::Enum* enum_type =
423 typeinfo->GetEnumByTypeUrl(field.type_url());
424 if (!enum_type) {
425 GOOGLE_LOG(WARNING) << "Could not find enum with type '" << field.type_url()
426 << "'";
427 return DataPiece::NullData();
428 }
429 // We treat the first value as the default if none is specified.
430 return enum_type->enumvalue_size() > 0
431 ? (use_ints_for_enums
432 ? DataPiece(enum_type->enumvalue(0).number())
433 : DataPiece(enum_type->enumvalue(0).name(), true))
434 : DataPiece::NullData();
435 }
436
CreateDefaultDataPieceForField(const google::protobuf::Field & field,const TypeInfo * typeinfo,bool use_ints_for_enums)437 DataPiece DefaultValueObjectWriter::CreateDefaultDataPieceForField(
438 const google::protobuf::Field& field, const TypeInfo* typeinfo,
439 bool use_ints_for_enums) {
440 switch (field.kind()) {
441 case google::protobuf::Field_Kind_TYPE_DOUBLE: {
442 return DataPiece(ConvertTo<double>(
443 field.default_value(), &DataPiece::ToDouble, static_cast<double>(0)));
444 }
445 case google::protobuf::Field_Kind_TYPE_FLOAT: {
446 return DataPiece(ConvertTo<float>(
447 field.default_value(), &DataPiece::ToFloat, static_cast<float>(0)));
448 }
449 case google::protobuf::Field_Kind_TYPE_INT64:
450 case google::protobuf::Field_Kind_TYPE_SINT64:
451 case google::protobuf::Field_Kind_TYPE_SFIXED64: {
452 return DataPiece(ConvertTo<int64>(
453 field.default_value(), &DataPiece::ToInt64, static_cast<int64>(0)));
454 }
455 case google::protobuf::Field_Kind_TYPE_UINT64:
456 case google::protobuf::Field_Kind_TYPE_FIXED64: {
457 return DataPiece(ConvertTo<uint64>(
458 field.default_value(), &DataPiece::ToUint64, static_cast<uint64>(0)));
459 }
460 case google::protobuf::Field_Kind_TYPE_INT32:
461 case google::protobuf::Field_Kind_TYPE_SINT32:
462 case google::protobuf::Field_Kind_TYPE_SFIXED32: {
463 return DataPiece(ConvertTo<int32>(
464 field.default_value(), &DataPiece::ToInt32, static_cast<int32>(0)));
465 }
466 case google::protobuf::Field_Kind_TYPE_BOOL: {
467 return DataPiece(
468 ConvertTo<bool>(field.default_value(), &DataPiece::ToBool, false));
469 }
470 case google::protobuf::Field_Kind_TYPE_STRING: {
471 return DataPiece(field.default_value(), true);
472 }
473 case google::protobuf::Field_Kind_TYPE_BYTES: {
474 return DataPiece(field.default_value(), false, true);
475 }
476 case google::protobuf::Field_Kind_TYPE_UINT32:
477 case google::protobuf::Field_Kind_TYPE_FIXED32: {
478 return DataPiece(ConvertTo<uint32>(
479 field.default_value(), &DataPiece::ToUint32, static_cast<uint32>(0)));
480 }
481 case google::protobuf::Field_Kind_TYPE_ENUM: {
482 return FindEnumDefault(field, typeinfo, use_ints_for_enums);
483 }
484 default: {
485 return DataPiece::NullData();
486 }
487 }
488 }
489
StartObject(StringPiece name)490 DefaultValueObjectWriter* DefaultValueObjectWriter::StartObject(
491 StringPiece name) {
492 if (current_ == nullptr) {
493 std::vector<std::string> path;
494 root_.reset(CreateNewNode(
495 std::string(name), &type_, OBJECT, DataPiece::NullData(), false, path,
496 suppress_empty_list_, preserve_proto_field_names_, use_ints_for_enums_,
497 field_scrub_callback_.get()));
498 root_->PopulateChildren(typeinfo_);
499 current_ = root_.get();
500 return this;
501 }
502 MaybePopulateChildrenOfAny(current_);
503 Node* child = current_->FindChild(name);
504 if (current_->kind() == LIST || current_->kind() == MAP || child == nullptr) {
505 // If current_ is a list or a map node, we should create a new child and use
506 // the type of current_ as the type of the new child.
507 std::unique_ptr<Node> node(
508 CreateNewNode(std::string(name),
509 ((current_->kind() == LIST || current_->kind() == MAP)
510 ? current_->type()
511 : nullptr),
512 OBJECT, DataPiece::NullData(), false,
513 child == nullptr ? current_->path() : child->path(),
514 suppress_empty_list_, preserve_proto_field_names_,
515 use_ints_for_enums_, field_scrub_callback_.get()));
516 child = node.get();
517 current_->AddChild(node.release());
518 }
519
520 child->set_is_placeholder(false);
521 if (child->kind() == OBJECT && child->number_of_children() == 0) {
522 child->PopulateChildren(typeinfo_);
523 }
524
525 stack_.push(current_);
526 current_ = child;
527 return this;
528 }
529
EndObject()530 DefaultValueObjectWriter* DefaultValueObjectWriter::EndObject() {
531 if (stack_.empty()) {
532 // The root object ends here. Writes out the tree.
533 WriteRoot();
534 return this;
535 }
536 current_ = stack_.top();
537 stack_.pop();
538 return this;
539 }
540
StartList(StringPiece name)541 DefaultValueObjectWriter* DefaultValueObjectWriter::StartList(
542 StringPiece name) {
543 if (current_ == nullptr) {
544 std::vector<std::string> path;
545 root_.reset(CreateNewNode(
546 std::string(name), &type_, LIST, DataPiece::NullData(), false, path,
547 suppress_empty_list_, preserve_proto_field_names_, use_ints_for_enums_,
548 field_scrub_callback_.get()));
549 current_ = root_.get();
550 return this;
551 }
552 MaybePopulateChildrenOfAny(current_);
553 Node* child = current_->FindChild(name);
554 if (child == nullptr || child->kind() != LIST) {
555 std::unique_ptr<Node> node(CreateNewNode(
556 std::string(name), nullptr, LIST, DataPiece::NullData(), false,
557 child == nullptr ? current_->path() : child->path(),
558 suppress_empty_list_, preserve_proto_field_names_, use_ints_for_enums_,
559 field_scrub_callback_.get()));
560 child = node.get();
561 current_->AddChild(node.release());
562 }
563 child->set_is_placeholder(false);
564
565 stack_.push(current_);
566 current_ = child;
567 return this;
568 }
569
WriteRoot()570 void DefaultValueObjectWriter::WriteRoot() {
571 root_->WriteTo(ow_);
572 root_.reset(nullptr);
573 current_ = nullptr;
574 }
575
EndList()576 DefaultValueObjectWriter* DefaultValueObjectWriter::EndList() {
577 if (stack_.empty()) {
578 WriteRoot();
579 return this;
580 }
581 current_ = stack_.top();
582 stack_.pop();
583 return this;
584 }
585
RenderDataPiece(StringPiece name,const DataPiece & data)586 void DefaultValueObjectWriter::RenderDataPiece(StringPiece name,
587 const DataPiece& data) {
588 MaybePopulateChildrenOfAny(current_);
589 if (current_->type() != nullptr && current_->type()->name() == kAnyType &&
590 name == "@type") {
591 util::StatusOr<std::string> data_string = data.ToString();
592 if (data_string.ok()) {
593 const std::string& string_value = data_string.ValueOrDie();
594 // If the type of current_ is "Any" and its "@type" field is being set
595 // here, sets the type of current_ to be the type specified by the
596 // "@type".
597 util::StatusOr<const google::protobuf::Type*> found_type =
598 typeinfo_->ResolveTypeUrl(string_value);
599 if (!found_type.ok()) {
600 GOOGLE_LOG(WARNING) << "Failed to resolve type '" << string_value << "'.";
601 } else {
602 current_->set_type(found_type.ValueOrDie());
603 }
604 current_->set_is_any(true);
605 // If the "@type" field is placed after other fields, we should populate
606 // other children of primitive type now. Otherwise, we should wait until
607 // the first value field is rendered before we populate the children,
608 // because the "value" field of a Any message could be omitted.
609 if (current_->number_of_children() > 1 && current_->type() != nullptr) {
610 current_->PopulateChildren(typeinfo_);
611 }
612 }
613 }
614 Node* child = current_->FindChild(name);
615 if (child == nullptr || child->kind() != PRIMITIVE) {
616 // No children are found, creates a new child.
617 std::unique_ptr<Node> node(
618 CreateNewNode(std::string(name), nullptr, PRIMITIVE, data, false,
619 child == nullptr ? current_->path() : child->path(),
620 suppress_empty_list_, preserve_proto_field_names_,
621 use_ints_for_enums_, field_scrub_callback_.get()));
622 current_->AddChild(node.release());
623 } else {
624 child->set_data(data);
625 child->set_is_placeholder(false);
626 }
627 }
628
629 } // namespace converter
630 } // namespace util
631 } // namespace protobuf
632 } // namespace google
633