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.value() : 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 ow_(ow) {}
71
~DefaultValueObjectWriter()72 DefaultValueObjectWriter::~DefaultValueObjectWriter() {
73 if (own_typeinfo_) {
74 delete typeinfo_;
75 }
76 }
77
RenderBool(StringPiece name,bool value)78 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderBool(
79 StringPiece name, bool value) {
80 if (current_ == nullptr) {
81 ow_->RenderBool(name, value);
82 } else {
83 RenderDataPiece(name, DataPiece(value));
84 }
85 return this;
86 }
87
RenderInt32(StringPiece name,int32 value)88 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderInt32(
89 StringPiece name, int32 value) {
90 if (current_ == nullptr) {
91 ow_->RenderInt32(name, value);
92 } else {
93 RenderDataPiece(name, DataPiece(value));
94 }
95 return this;
96 }
97
RenderUint32(StringPiece name,uint32 value)98 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderUint32(
99 StringPiece name, uint32 value) {
100 if (current_ == nullptr) {
101 ow_->RenderUint32(name, value);
102 } else {
103 RenderDataPiece(name, DataPiece(value));
104 }
105 return this;
106 }
107
RenderInt64(StringPiece name,int64 value)108 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderInt64(
109 StringPiece name, int64 value) {
110 if (current_ == nullptr) {
111 ow_->RenderInt64(name, value);
112 } else {
113 RenderDataPiece(name, DataPiece(value));
114 }
115 return this;
116 }
117
RenderUint64(StringPiece name,uint64 value)118 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderUint64(
119 StringPiece name, uint64 value) {
120 if (current_ == nullptr) {
121 ow_->RenderUint64(name, value);
122 } else {
123 RenderDataPiece(name, DataPiece(value));
124 }
125 return this;
126 }
127
RenderDouble(StringPiece name,double value)128 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderDouble(
129 StringPiece name, double value) {
130 if (current_ == nullptr) {
131 ow_->RenderDouble(name, value);
132 } else {
133 RenderDataPiece(name, DataPiece(value));
134 }
135 return this;
136 }
137
RenderFloat(StringPiece name,float value)138 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderFloat(
139 StringPiece name, float value) {
140 if (current_ == nullptr) {
141 ow_->RenderBool(name, value);
142 } else {
143 RenderDataPiece(name, DataPiece(value));
144 }
145 return this;
146 }
147
RenderString(StringPiece name,StringPiece value)148 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderString(
149 StringPiece name, StringPiece value) {
150 if (current_ == nullptr) {
151 ow_->RenderString(name, value);
152 } else {
153 // Since StringPiece is essentially a pointer, takes a copy of "value" to
154 // avoid ownership issues.
155 string_values_.emplace_back(new std::string(value));
156 RenderDataPiece(name, DataPiece(*string_values_.back(), true));
157 }
158 return this;
159 }
160
RenderBytes(StringPiece name,StringPiece value)161 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderBytes(
162 StringPiece name, StringPiece value) {
163 if (current_ == nullptr) {
164 ow_->RenderBytes(name, value);
165 } else {
166 // Since StringPiece is essentially a pointer, takes a copy of "value" to
167 // avoid ownership issues.
168 string_values_.emplace_back(new std::string(value));
169 RenderDataPiece(name, DataPiece(*string_values_.back(), false, true));
170 }
171 return this;
172 }
173
RenderNull(StringPiece name)174 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderNull(
175 StringPiece name) {
176 if (current_ == nullptr) {
177 ow_->RenderNull(name);
178 } else {
179 RenderDataPiece(name, DataPiece::NullData());
180 }
181 return this;
182 }
183
RegisterFieldScrubCallBack(FieldScrubCallBack field_scrub_callback)184 void DefaultValueObjectWriter::RegisterFieldScrubCallBack(
185 FieldScrubCallBack field_scrub_callback) {
186 field_scrub_callback_ = std::move(field_scrub_callback);
187 }
188
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)189 DefaultValueObjectWriter::Node* DefaultValueObjectWriter::CreateNewNode(
190 const std::string& name, const google::protobuf::Type* type, NodeKind kind,
191 const DataPiece& data, bool is_placeholder,
192 const std::vector<std::string>& path, bool suppress_empty_list,
193 bool preserve_proto_field_names, bool use_ints_for_enums,
194 FieldScrubCallBack field_scrub_callback) {
195 return new Node(name, type, kind, data, is_placeholder, path,
196 suppress_empty_list, preserve_proto_field_names,
197 use_ints_for_enums, std::move(field_scrub_callback));
198 }
199
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)200 DefaultValueObjectWriter::Node::Node(
201 const std::string& name, const google::protobuf::Type* type, NodeKind kind,
202 const DataPiece& data, bool is_placeholder,
203 const std::vector<std::string>& path, bool suppress_empty_list,
204 bool preserve_proto_field_names, bool use_ints_for_enums,
205 FieldScrubCallBack field_scrub_callback)
206 : name_(name),
207 type_(type),
208 kind_(kind),
209 is_any_(false),
210 data_(data),
211 is_placeholder_(is_placeholder),
212 path_(path),
213 suppress_empty_list_(suppress_empty_list),
214 preserve_proto_field_names_(preserve_proto_field_names),
215 use_ints_for_enums_(use_ints_for_enums),
216 field_scrub_callback_(std::move(field_scrub_callback)) {}
217
FindChild(StringPiece name)218 DefaultValueObjectWriter::Node* DefaultValueObjectWriter::Node::FindChild(
219 StringPiece name) {
220 if (name.empty() || kind_ != OBJECT) {
221 return nullptr;
222 }
223 for (int i = 0; i < children_.size(); ++i) {
224 Node* child = children_[i];
225 if (child->name() == name) {
226 return child;
227 }
228 }
229 return nullptr;
230 }
231
WriteTo(ObjectWriter * ow)232 void DefaultValueObjectWriter::Node::WriteTo(ObjectWriter* ow) {
233 if (kind_ == PRIMITIVE) {
234 ObjectWriter::RenderDataPieceTo(data_, name_, ow);
235 return;
236 }
237
238 // Render maps. Empty maps are rendered as "{}".
239 if (kind_ == MAP) {
240 ow->StartObject(name_);
241 WriteChildren(ow);
242 ow->EndObject();
243 return;
244 }
245
246 // Write out lists. If we didn't have any list in response, write out empty
247 // list.
248 if (kind_ == LIST) {
249 // Suppress empty lists if requested.
250 if (suppress_empty_list_ && is_placeholder_) return;
251
252 ow->StartList(name_);
253 WriteChildren(ow);
254 ow->EndList();
255 return;
256 }
257
258 // If is_placeholder_ = true, we didn't see this node in the response, so
259 // skip output.
260 if (is_placeholder_) return;
261
262 ow->StartObject(name_);
263 WriteChildren(ow);
264 ow->EndObject();
265 }
266
WriteChildren(ObjectWriter * ow)267 void DefaultValueObjectWriter::Node::WriteChildren(ObjectWriter* ow) {
268 for (int i = 0; i < children_.size(); ++i) {
269 Node* child = children_[i];
270 child->WriteTo(ow);
271 }
272 }
273
GetMapValueType(const google::protobuf::Type & found_type,const TypeInfo * typeinfo)274 const google::protobuf::Type* DefaultValueObjectWriter::Node::GetMapValueType(
275 const google::protobuf::Type& found_type, const TypeInfo* typeinfo) {
276 // If this field is a map, we should use the type of its "Value" as
277 // the type of the child node.
278 for (int i = 0; i < found_type.fields_size(); ++i) {
279 const google::protobuf::Field& sub_field = found_type.fields(i);
280 if (sub_field.number() != 2) {
281 continue;
282 }
283 if (sub_field.kind() != google::protobuf::Field::TYPE_MESSAGE) {
284 // This map's value type is not a message type. We don't need to
285 // get the field_type in this case.
286 break;
287 }
288 util::StatusOr<const google::protobuf::Type*> sub_type =
289 typeinfo->ResolveTypeUrl(sub_field.type_url());
290 if (!sub_type.ok()) {
291 GOOGLE_LOG(WARNING) << "Cannot resolve type '" << sub_field.type_url() << "'.";
292 } else {
293 return sub_type.value();
294 }
295 break;
296 }
297 return nullptr;
298 }
299
PopulateChildren(const TypeInfo * typeinfo)300 void DefaultValueObjectWriter::Node::PopulateChildren(
301 const TypeInfo* typeinfo) {
302 // Ignores well known types that don't require automatically populating their
303 // primitive children. For type "Any", we only populate its children when the
304 // "@type" field is set.
305 // TODO(tsun): remove "kStructValueType" from the list. It's being checked
306 // now because of a bug in the tool-chain that causes the "oneof_index"
307 // of kStructValueType to not be set correctly.
308 if (type_ == nullptr || type_->name() == kAnyType ||
309 type_->name() == kStructType || type_->name() == kTimestampType ||
310 type_->name() == kDurationType || type_->name() == kStructValueType) {
311 return;
312 }
313 std::vector<Node*> new_children;
314 std::unordered_map<std::string, int> orig_children_map;
315
316 // Creates a map of child nodes to speed up lookup.
317 for (int i = 0; i < children_.size(); ++i) {
318 InsertIfNotPresent(&orig_children_map, children_[i]->name_, i);
319 }
320
321 for (int i = 0; i < type_->fields_size(); ++i) {
322 const google::protobuf::Field& field = type_->fields(i);
323
324 // This code is checking if the field to be added to the tree should be
325 // scrubbed or not by calling the field_scrub_callback_ callback function.
326 std::vector<std::string> path;
327 if (!path_.empty()) {
328 path.insert(path.begin(), path_.begin(), path_.end());
329 }
330 path.push_back(field.name());
331 if (field_scrub_callback_ && field_scrub_callback_(path, &field)) {
332 continue;
333 }
334
335 std::unordered_map<std::string, int>::iterator found =
336 orig_children_map.find(field.name());
337 // If the child field has already been set, we just add it to the new list
338 // of children.
339 if (found != orig_children_map.end()) {
340 new_children.push_back(children_[found->second]);
341 children_[found->second] = nullptr;
342 continue;
343 }
344
345 const google::protobuf::Type* field_type = nullptr;
346 bool is_map = false;
347 NodeKind kind = PRIMITIVE;
348
349 if (field.kind() == google::protobuf::Field::TYPE_MESSAGE) {
350 kind = OBJECT;
351 util::StatusOr<const google::protobuf::Type*> found_result =
352 typeinfo->ResolveTypeUrl(field.type_url());
353 if (!found_result.ok()) {
354 // "field" is of an unknown type.
355 GOOGLE_LOG(WARNING) << "Cannot resolve type '" << field.type_url() << "'.";
356 } else {
357 const google::protobuf::Type* found_type = found_result.value();
358 is_map = IsMap(field, *found_type);
359
360 if (!is_map) {
361 field_type = found_type;
362 } else {
363 // If this field is a map, we should use the type of its "Value" as
364 // the type of the child node.
365 field_type = GetMapValueType(*found_type, typeinfo);
366 kind = MAP;
367 }
368 }
369 }
370
371 if (!is_map &&
372 field.cardinality() == google::protobuf::Field::CARDINALITY_REPEATED) {
373 kind = LIST;
374 }
375
376 // If oneof_index() != 0, the child field is part of a "oneof", which means
377 // the child field is optional and we shouldn't populate its default
378 // primitive value.
379 if (field.oneof_index() != 0 && kind == PRIMITIVE) continue;
380
381 // If the child field is of primitive type, sets its data to the default
382 // value of its type.
383 std::unique_ptr<Node> child(
384 new Node(preserve_proto_field_names_ ? field.name() : field.json_name(),
385 field_type, kind,
386 kind == PRIMITIVE ? CreateDefaultDataPieceForField(
387 field, typeinfo, use_ints_for_enums_)
388 : DataPiece::NullData(),
389 true, path, suppress_empty_list_, preserve_proto_field_names_,
390 use_ints_for_enums_, field_scrub_callback_));
391 new_children.push_back(child.release());
392 }
393 // Adds all leftover nodes in children_ to the beginning of new_child.
394 for (int i = 0; i < children_.size(); ++i) {
395 if (children_[i] == nullptr) {
396 continue;
397 }
398 new_children.insert(new_children.begin(), children_[i]);
399 children_[i] = nullptr;
400 }
401 children_.swap(new_children);
402 }
403
MaybePopulateChildrenOfAny(Node * node)404 void DefaultValueObjectWriter::MaybePopulateChildrenOfAny(Node* node) {
405 // If this is an "Any" node with "@type" already given and no other children
406 // have been added, populates its children.
407 if (node != nullptr && node->is_any() && node->type() != nullptr &&
408 node->type()->name() != kAnyType && node->number_of_children() == 1) {
409 node->PopulateChildren(typeinfo_);
410 }
411 }
412
FindEnumDefault(const google::protobuf::Field & field,const TypeInfo * typeinfo,bool use_ints_for_enums)413 DataPiece DefaultValueObjectWriter::FindEnumDefault(
414 const google::protobuf::Field& field, const TypeInfo* typeinfo,
415 bool use_ints_for_enums) {
416 if (!field.default_value().empty())
417 return DataPiece(field.default_value(), true);
418
419 const google::protobuf::Enum* enum_type =
420 typeinfo->GetEnumByTypeUrl(field.type_url());
421 if (!enum_type) {
422 GOOGLE_LOG(WARNING) << "Could not find enum with type '" << field.type_url()
423 << "'";
424 return DataPiece::NullData();
425 }
426 // We treat the first value as the default if none is specified.
427 return enum_type->enumvalue_size() > 0
428 ? (use_ints_for_enums
429 ? DataPiece(enum_type->enumvalue(0).number())
430 : DataPiece(enum_type->enumvalue(0).name(), true))
431 : DataPiece::NullData();
432 }
433
CreateDefaultDataPieceForField(const google::protobuf::Field & field,const TypeInfo * typeinfo,bool use_ints_for_enums)434 DataPiece DefaultValueObjectWriter::CreateDefaultDataPieceForField(
435 const google::protobuf::Field& field, const TypeInfo* typeinfo,
436 bool use_ints_for_enums) {
437 switch (field.kind()) {
438 case google::protobuf::Field::TYPE_DOUBLE: {
439 return DataPiece(ConvertTo<double>(
440 field.default_value(), &DataPiece::ToDouble, static_cast<double>(0)));
441 }
442 case google::protobuf::Field::TYPE_FLOAT: {
443 return DataPiece(ConvertTo<float>(
444 field.default_value(), &DataPiece::ToFloat, static_cast<float>(0)));
445 }
446 case google::protobuf::Field::TYPE_INT64:
447 case google::protobuf::Field::TYPE_SINT64:
448 case google::protobuf::Field::TYPE_SFIXED64: {
449 return DataPiece(ConvertTo<int64>(
450 field.default_value(), &DataPiece::ToInt64, static_cast<int64>(0)));
451 }
452 case google::protobuf::Field::TYPE_UINT64:
453 case google::protobuf::Field::TYPE_FIXED64: {
454 return DataPiece(ConvertTo<uint64>(
455 field.default_value(), &DataPiece::ToUint64, static_cast<uint64>(0)));
456 }
457 case google::protobuf::Field::TYPE_INT32:
458 case google::protobuf::Field::TYPE_SINT32:
459 case google::protobuf::Field::TYPE_SFIXED32: {
460 return DataPiece(ConvertTo<int32>(
461 field.default_value(), &DataPiece::ToInt32, static_cast<int32>(0)));
462 }
463 case google::protobuf::Field::TYPE_BOOL: {
464 return DataPiece(
465 ConvertTo<bool>(field.default_value(), &DataPiece::ToBool, false));
466 }
467 case google::protobuf::Field::TYPE_STRING: {
468 return DataPiece(field.default_value(), true);
469 }
470 case google::protobuf::Field::TYPE_BYTES: {
471 return DataPiece(field.default_value(), false, true);
472 }
473 case google::protobuf::Field::TYPE_UINT32:
474 case google::protobuf::Field::TYPE_FIXED32: {
475 return DataPiece(ConvertTo<uint32>(
476 field.default_value(), &DataPiece::ToUint32, static_cast<uint32>(0)));
477 }
478 case google::protobuf::Field::TYPE_ENUM: {
479 return FindEnumDefault(field, typeinfo, use_ints_for_enums);
480 }
481 default: {
482 return DataPiece::NullData();
483 }
484 }
485 }
486
StartObject(StringPiece name)487 DefaultValueObjectWriter* DefaultValueObjectWriter::StartObject(
488 StringPiece name) {
489 if (current_ == nullptr) {
490 std::vector<std::string> path;
491 root_.reset(CreateNewNode(std::string(name), &type_, OBJECT,
492 DataPiece::NullData(), false, path,
493 suppress_empty_list_, preserve_proto_field_names_,
494 use_ints_for_enums_, field_scrub_callback_));
495 root_->PopulateChildren(typeinfo_);
496 current_ = root_.get();
497 return this;
498 }
499 MaybePopulateChildrenOfAny(current_);
500 Node* child = current_->FindChild(name);
501 if (current_->kind() == LIST || current_->kind() == MAP || child == nullptr) {
502 // If current_ is a list or a map node, we should create a new child and use
503 // the type of current_ as the type of the new child.
504 std::unique_ptr<Node> node(
505 CreateNewNode(std::string(name),
506 ((current_->kind() == LIST || current_->kind() == MAP)
507 ? current_->type()
508 : nullptr),
509 OBJECT, DataPiece::NullData(), false,
510 child == nullptr ? current_->path() : child->path(),
511 suppress_empty_list_, preserve_proto_field_names_,
512 use_ints_for_enums_, field_scrub_callback_));
513 child = node.get();
514 current_->AddChild(node.release());
515 }
516
517 child->set_is_placeholder(false);
518 if (child->kind() == OBJECT && child->number_of_children() == 0) {
519 child->PopulateChildren(typeinfo_);
520 }
521
522 stack_.push(current_);
523 current_ = child;
524 return this;
525 }
526
EndObject()527 DefaultValueObjectWriter* DefaultValueObjectWriter::EndObject() {
528 if (stack_.empty()) {
529 // The root object ends here. Writes out the tree.
530 WriteRoot();
531 return this;
532 }
533 current_ = stack_.top();
534 stack_.pop();
535 return this;
536 }
537
StartList(StringPiece name)538 DefaultValueObjectWriter* DefaultValueObjectWriter::StartList(
539 StringPiece name) {
540 if (current_ == nullptr) {
541 std::vector<std::string> path;
542 root_.reset(CreateNewNode(std::string(name), &type_, LIST,
543 DataPiece::NullData(), false, path,
544 suppress_empty_list_, preserve_proto_field_names_,
545 use_ints_for_enums_, field_scrub_callback_));
546 current_ = root_.get();
547 return this;
548 }
549 MaybePopulateChildrenOfAny(current_);
550 Node* child = current_->FindChild(name);
551 if (child == nullptr || child->kind() != LIST) {
552 std::unique_ptr<Node> node(CreateNewNode(
553 std::string(name), nullptr, LIST, DataPiece::NullData(), false,
554 child == nullptr ? current_->path() : child->path(),
555 suppress_empty_list_, preserve_proto_field_names_, use_ints_for_enums_,
556 field_scrub_callback_));
557 child = node.get();
558 current_->AddChild(node.release());
559 }
560 child->set_is_placeholder(false);
561
562 stack_.push(current_);
563 current_ = child;
564 return this;
565 }
566
WriteRoot()567 void DefaultValueObjectWriter::WriteRoot() {
568 root_->WriteTo(ow_);
569 root_.reset(nullptr);
570 current_ = nullptr;
571 }
572
EndList()573 DefaultValueObjectWriter* DefaultValueObjectWriter::EndList() {
574 if (stack_.empty()) {
575 WriteRoot();
576 return this;
577 }
578 current_ = stack_.top();
579 stack_.pop();
580 return this;
581 }
582
RenderDataPiece(StringPiece name,const DataPiece & data)583 void DefaultValueObjectWriter::RenderDataPiece(StringPiece name,
584 const DataPiece& data) {
585 MaybePopulateChildrenOfAny(current_);
586 if (current_->type() != nullptr && current_->type()->name() == kAnyType &&
587 name == "@type") {
588 util::StatusOr<std::string> data_string = data.ToString();
589 if (data_string.ok()) {
590 const std::string& string_value = data_string.value();
591 // If the type of current_ is "Any" and its "@type" field is being set
592 // here, sets the type of current_ to be the type specified by the
593 // "@type".
594 util::StatusOr<const google::protobuf::Type*> found_type =
595 typeinfo_->ResolveTypeUrl(string_value);
596 if (!found_type.ok()) {
597 GOOGLE_LOG(WARNING) << "Failed to resolve type '" << string_value << "'.";
598 } else {
599 current_->set_type(found_type.value());
600 }
601 current_->set_is_any(true);
602 // If the "@type" field is placed after other fields, we should populate
603 // other children of primitive type now. Otherwise, we should wait until
604 // the first value field is rendered before we populate the children,
605 // because the "value" field of a Any message could be omitted.
606 if (current_->number_of_children() > 1 && current_->type() != nullptr) {
607 current_->PopulateChildren(typeinfo_);
608 }
609 }
610 }
611 Node* child = current_->FindChild(name);
612 if (child == nullptr || child->kind() != PRIMITIVE) {
613 // No children are found, creates a new child.
614 std::unique_ptr<Node> node(
615 CreateNewNode(std::string(name), nullptr, PRIMITIVE, data, false,
616 child == nullptr ? current_->path() : child->path(),
617 suppress_empty_list_, preserve_proto_field_names_,
618 use_ints_for_enums_, field_scrub_callback_));
619 current_->AddChild(node.release());
620 } else {
621 child->set_data(data);
622 child->set_is_placeholder(false);
623 }
624 }
625
626 } // namespace converter
627 } // namespace util
628 } // namespace protobuf
629 } // namespace google
630