OLD | NEW |
1 // Protocol Buffers - Google's data interchange format | 1 // Protocol Buffers - Google's data interchange format |
2 // Copyright 2008 Google Inc. All rights reserved. | 2 // Copyright 2008 Google Inc. All rights reserved. |
3 // https://developers.google.com/protocol-buffers/ | 3 // https://developers.google.com/protocol-buffers/ |
4 // | 4 // |
5 // Redistribution and use in source and binary forms, with or without | 5 // Redistribution and use in source and binary forms, with or without |
6 // modification, are permitted provided that the following conditions are | 6 // modification, are permitted provided that the following conditions are |
7 // met: | 7 // met: |
8 // | 8 // |
9 // * Redistributions of source code must retain the above copyright | 9 // * Redistributions of source code must retain the above copyright |
10 // notice, this list of conditions and the following disclaimer. | 10 // notice, this list of conditions and the following disclaimer. |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
57 } // namespace | 57 } // namespace |
58 | 58 |
59 DefaultValueObjectWriter::DefaultValueObjectWriter( | 59 DefaultValueObjectWriter::DefaultValueObjectWriter( |
60 TypeResolver* type_resolver, const google::protobuf::Type& type, | 60 TypeResolver* type_resolver, const google::protobuf::Type& type, |
61 ObjectWriter* ow) | 61 ObjectWriter* ow) |
62 : typeinfo_(TypeInfo::NewTypeInfo(type_resolver)), | 62 : typeinfo_(TypeInfo::NewTypeInfo(type_resolver)), |
63 own_typeinfo_(true), | 63 own_typeinfo_(true), |
64 type_(type), | 64 type_(type), |
65 current_(NULL), | 65 current_(NULL), |
66 root_(NULL), | 66 root_(NULL), |
| 67 suppress_empty_list_(false), |
67 field_scrub_callback_(NULL), | 68 field_scrub_callback_(NULL), |
68 ow_(ow) {} | 69 ow_(ow) {} |
69 | 70 |
70 DefaultValueObjectWriter::~DefaultValueObjectWriter() { | 71 DefaultValueObjectWriter::~DefaultValueObjectWriter() { |
71 for (int i = 0; i < string_values_.size(); ++i) { | 72 for (int i = 0; i < string_values_.size(); ++i) { |
72 delete string_values_[i]; | 73 delete string_values_[i]; |
73 } | 74 } |
74 if (own_typeinfo_) { | 75 if (own_typeinfo_) { |
75 delete typeinfo_; | 76 delete typeinfo_; |
76 } | 77 } |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
157 RenderDataPiece(name, DataPiece(*string_values_.back(), true)); | 158 RenderDataPiece(name, DataPiece(*string_values_.back(), true)); |
158 } | 159 } |
159 return this; | 160 return this; |
160 } | 161 } |
161 | 162 |
162 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderBytes( | 163 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderBytes( |
163 StringPiece name, StringPiece value) { | 164 StringPiece name, StringPiece value) { |
164 if (current_ == NULL) { | 165 if (current_ == NULL) { |
165 ow_->RenderBytes(name, value); | 166 ow_->RenderBytes(name, value); |
166 } else { | 167 } else { |
167 RenderDataPiece(name, DataPiece(value, false, true)); | 168 // Since StringPiece is essentially a pointer, takes a copy of "value" to |
| 169 // avoid ownership issues. |
| 170 string_values_.push_back(new string(value.ToString())); |
| 171 RenderDataPiece(name, DataPiece(*string_values_.back(), false, true)); |
168 } | 172 } |
169 return this; | 173 return this; |
170 } | 174 } |
171 | 175 |
172 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderNull( | 176 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderNull( |
173 StringPiece name) { | 177 StringPiece name) { |
174 if (current_ == NULL) { | 178 if (current_ == NULL) { |
175 ow_->RenderNull(name); | 179 ow_->RenderNull(name); |
176 } else { | 180 } else { |
177 RenderDataPiece(name, DataPiece::NullData()); | 181 RenderDataPiece(name, DataPiece::NullData()); |
178 } | 182 } |
179 return this; | 183 return this; |
180 } | 184 } |
181 | 185 |
182 void DefaultValueObjectWriter::RegisterFieldScrubCallBack( | 186 void DefaultValueObjectWriter::RegisterFieldScrubCallBack( |
183 FieldScrubCallBackPtr field_scrub_callback) { | 187 FieldScrubCallBackPtr field_scrub_callback) { |
184 field_scrub_callback_.reset(field_scrub_callback.release()); | 188 field_scrub_callback_.reset(field_scrub_callback.release()); |
185 } | 189 } |
186 | 190 |
187 DefaultValueObjectWriter::Node::Node(const string& name, | 191 DefaultValueObjectWriter::Node::Node( |
188 const google::protobuf::Type* type, | 192 const string& name, const google::protobuf::Type* type, NodeKind kind, |
189 NodeKind kind, const DataPiece& data, | 193 const DataPiece& data, bool is_placeholder, const std::vector<string>& path, |
190 bool is_placeholder, | 194 bool suppress_empty_list, FieldScrubCallBack* field_scrub_callback) |
191 const vector<string>& path, | |
192 FieldScrubCallBack* field_scrub_callback) | |
193 : name_(name), | 195 : name_(name), |
194 type_(type), | 196 type_(type), |
195 kind_(kind), | 197 kind_(kind), |
196 is_any_(false), | 198 is_any_(false), |
197 data_(data), | 199 data_(data), |
198 is_placeholder_(is_placeholder), | 200 is_placeholder_(is_placeholder), |
199 path_(path), | 201 path_(path), |
| 202 suppress_empty_list_(suppress_empty_list), |
200 field_scrub_callback_(field_scrub_callback) {} | 203 field_scrub_callback_(field_scrub_callback) {} |
201 | 204 |
202 DefaultValueObjectWriter::Node* DefaultValueObjectWriter::Node::FindChild( | 205 DefaultValueObjectWriter::Node* DefaultValueObjectWriter::Node::FindChild( |
203 StringPiece name) { | 206 StringPiece name) { |
204 if (name.empty() || kind_ != OBJECT) { | 207 if (name.empty() || kind_ != OBJECT) { |
205 return NULL; | 208 return NULL; |
206 } | 209 } |
207 for (int i = 0; i < children_.size(); ++i) { | 210 for (int i = 0; i < children_.size(); ++i) { |
208 Node* child = children_[i]; | 211 Node* child = children_[i]; |
209 if (child->name() == name) { | 212 if (child->name() == name) { |
(...skipping 13 matching lines...) Expand all Loading... |
223 if (kind_ == MAP) { | 226 if (kind_ == MAP) { |
224 ow->StartObject(name_); | 227 ow->StartObject(name_); |
225 WriteChildren(ow); | 228 WriteChildren(ow); |
226 ow->EndObject(); | 229 ow->EndObject(); |
227 return; | 230 return; |
228 } | 231 } |
229 | 232 |
230 // Write out lists. If we didn't have any list in response, write out empty | 233 // Write out lists. If we didn't have any list in response, write out empty |
231 // list. | 234 // list. |
232 if (kind_ == LIST) { | 235 if (kind_ == LIST) { |
| 236 // Suppress empty lists if requested. |
| 237 if (suppress_empty_list_ && is_placeholder_) return; |
| 238 |
233 ow->StartList(name_); | 239 ow->StartList(name_); |
234 WriteChildren(ow); | 240 WriteChildren(ow); |
235 ow->EndList(); | 241 ow->EndList(); |
236 return; | 242 return; |
237 } | 243 } |
238 | 244 |
239 // If is_placeholder_ = true, we didn't see this node in the response, so | 245 // If is_placeholder_ = true, we didn't see this node in the response, so |
240 // skip output. | 246 // skip output. |
241 if (is_placeholder_) return; | 247 if (is_placeholder_) return; |
242 | 248 |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
297 // Creates a map of child nodes to speed up lookup. | 303 // Creates a map of child nodes to speed up lookup. |
298 for (int i = 0; i < children_.size(); ++i) { | 304 for (int i = 0; i < children_.size(); ++i) { |
299 InsertIfNotPresent(&orig_children_map, children_[i]->name_, i); | 305 InsertIfNotPresent(&orig_children_map, children_[i]->name_, i); |
300 } | 306 } |
301 | 307 |
302 for (int i = 0; i < type_->fields_size(); ++i) { | 308 for (int i = 0; i < type_->fields_size(); ++i) { |
303 const google::protobuf::Field& field = type_->fields(i); | 309 const google::protobuf::Field& field = type_->fields(i); |
304 | 310 |
305 // This code is checking if the field to be added to the tree should be | 311 // This code is checking if the field to be added to the tree should be |
306 // scrubbed or not by calling the field_scrub_callback_ callback function. | 312 // scrubbed or not by calling the field_scrub_callback_ callback function. |
307 vector<string> path; | 313 std::vector<string> path; |
308 if (!path_.empty()) { | 314 if (!path_.empty()) { |
309 path.insert(path.begin(), path_.begin(), path_.end()); | 315 path.insert(path.begin(), path_.begin(), path_.end()); |
310 } | 316 } |
311 path.push_back(field.name()); | 317 path.push_back(field.name()); |
312 if (field_scrub_callback_ != NULL && | 318 if (field_scrub_callback_ != NULL && |
313 field_scrub_callback_->Run(path, &field)) { | 319 field_scrub_callback_->Run(path, &field)) { |
314 continue; | 320 continue; |
315 } | 321 } |
316 | 322 |
317 hash_map<string, int>::iterator found = | 323 hash_map<string, int>::iterator found = |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
359 // If oneof_index() != 0, the child field is part of a "oneof", which means | 365 // If oneof_index() != 0, the child field is part of a "oneof", which means |
360 // the child field is optional and we shouldn't populate its default value. | 366 // the child field is optional and we shouldn't populate its default value. |
361 if (field.oneof_index() != 0) continue; | 367 if (field.oneof_index() != 0) continue; |
362 | 368 |
363 // If the child field is of primitive type, sets its data to the default | 369 // If the child field is of primitive type, sets its data to the default |
364 // value of its type. | 370 // value of its type. |
365 google::protobuf::scoped_ptr<Node> child(new Node( | 371 google::protobuf::scoped_ptr<Node> child(new Node( |
366 field.json_name(), field_type, kind, | 372 field.json_name(), field_type, kind, |
367 kind == PRIMITIVE ? CreateDefaultDataPieceForField(field, typeinfo) | 373 kind == PRIMITIVE ? CreateDefaultDataPieceForField(field, typeinfo) |
368 : DataPiece::NullData(), | 374 : DataPiece::NullData(), |
369 true, path, field_scrub_callback_)); | 375 true, path, suppress_empty_list_, field_scrub_callback_)); |
370 new_children.push_back(child.release()); | 376 new_children.push_back(child.release()); |
371 } | 377 } |
372 // Adds all leftover nodes in children_ to the beginning of new_child. | 378 // Adds all leftover nodes in children_ to the beginning of new_child. |
373 for (int i = 0; i < children_.size(); ++i) { | 379 for (int i = 0; i < children_.size(); ++i) { |
374 if (children_[i] == NULL) { | 380 if (children_[i] == NULL) { |
375 continue; | 381 continue; |
376 } | 382 } |
377 new_children.insert(new_children.begin(), children_[i]); | 383 new_children.insert(new_children.begin(), children_[i]); |
378 children_[i] = NULL; | 384 children_[i] = NULL; |
379 } | 385 } |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
453 case google::protobuf::Field_Kind_TYPE_ENUM: { | 459 case google::protobuf::Field_Kind_TYPE_ENUM: { |
454 return FindEnumDefault(field, typeinfo); | 460 return FindEnumDefault(field, typeinfo); |
455 } | 461 } |
456 default: { return DataPiece::NullData(); } | 462 default: { return DataPiece::NullData(); } |
457 } | 463 } |
458 } | 464 } |
459 | 465 |
460 DefaultValueObjectWriter* DefaultValueObjectWriter::StartObject( | 466 DefaultValueObjectWriter* DefaultValueObjectWriter::StartObject( |
461 StringPiece name) { | 467 StringPiece name) { |
462 if (current_ == NULL) { | 468 if (current_ == NULL) { |
463 vector<string> path; | 469 std::vector<string> path; |
464 root_.reset(new Node(name.ToString(), &type_, OBJECT, DataPiece::NullData(), | 470 root_.reset(new Node(name.ToString(), &type_, OBJECT, DataPiece::NullData(), |
465 false, path, field_scrub_callback_.get())); | 471 false, path, suppress_empty_list_, |
| 472 field_scrub_callback_.get())); |
466 root_->PopulateChildren(typeinfo_); | 473 root_->PopulateChildren(typeinfo_); |
467 current_ = root_.get(); | 474 current_ = root_.get(); |
468 return this; | 475 return this; |
469 } | 476 } |
470 MaybePopulateChildrenOfAny(current_); | 477 MaybePopulateChildrenOfAny(current_); |
471 Node* child = current_->FindChild(name); | 478 Node* child = current_->FindChild(name); |
472 if (current_->kind() == LIST || current_->kind() == MAP || child == NULL) { | 479 if (current_->kind() == LIST || current_->kind() == MAP || child == NULL) { |
473 // If current_ is a list or a map node, we should create a new child and use | 480 // If current_ is a list or a map node, we should create a new child and use |
474 // the type of current_ as the type of the new child. | 481 // the type of current_ as the type of the new child. |
475 google::protobuf::scoped_ptr<Node> node(new Node( | 482 google::protobuf::scoped_ptr<Node> node(new Node( |
476 name.ToString(), ((current_->kind() == LIST || current_->kind() == MAP) | 483 name.ToString(), ((current_->kind() == LIST || current_->kind() == MAP) |
477 ? current_->type() | 484 ? current_->type() |
478 : NULL), | 485 : NULL), |
479 OBJECT, DataPiece::NullData(), false, | 486 OBJECT, DataPiece::NullData(), false, |
480 child == NULL ? current_->path() : child->path(), | 487 child == NULL ? current_->path() : child->path(), |
481 field_scrub_callback_.get())); | 488 suppress_empty_list_, field_scrub_callback_.get())); |
482 child = node.get(); | 489 child = node.get(); |
483 current_->AddChild(node.release()); | 490 current_->AddChild(node.release()); |
484 } | 491 } |
485 | 492 |
486 child->set_is_placeholder(false); | 493 child->set_is_placeholder(false); |
487 if (child->kind() == OBJECT && child->number_of_children() == 0) { | 494 if (child->kind() == OBJECT && child->number_of_children() == 0) { |
488 child->PopulateChildren(typeinfo_); | 495 child->PopulateChildren(typeinfo_); |
489 } | 496 } |
490 | 497 |
491 stack_.push(current_); | 498 stack_.push(current_); |
492 current_ = child; | 499 current_ = child; |
493 return this; | 500 return this; |
494 } | 501 } |
495 | 502 |
496 DefaultValueObjectWriter* DefaultValueObjectWriter::EndObject() { | 503 DefaultValueObjectWriter* DefaultValueObjectWriter::EndObject() { |
497 if (stack_.empty()) { | 504 if (stack_.empty()) { |
498 // The root object ends here. Writes out the tree. | 505 // The root object ends here. Writes out the tree. |
499 WriteRoot(); | 506 WriteRoot(); |
500 return this; | 507 return this; |
501 } | 508 } |
502 current_ = stack_.top(); | 509 current_ = stack_.top(); |
503 stack_.pop(); | 510 stack_.pop(); |
504 return this; | 511 return this; |
505 } | 512 } |
506 | 513 |
507 DefaultValueObjectWriter* DefaultValueObjectWriter::StartList( | 514 DefaultValueObjectWriter* DefaultValueObjectWriter::StartList( |
508 StringPiece name) { | 515 StringPiece name) { |
509 if (current_ == NULL) { | 516 if (current_ == NULL) { |
510 vector<string> path; | 517 std::vector<string> path; |
511 root_.reset(new Node(name.ToString(), &type_, LIST, DataPiece::NullData(), | 518 root_.reset(new Node(name.ToString(), &type_, LIST, DataPiece::NullData(), |
512 false, path, field_scrub_callback_.get())); | 519 false, path, suppress_empty_list_, |
| 520 field_scrub_callback_.get())); |
513 current_ = root_.get(); | 521 current_ = root_.get(); |
514 return this; | 522 return this; |
515 } | 523 } |
516 MaybePopulateChildrenOfAny(current_); | 524 MaybePopulateChildrenOfAny(current_); |
517 Node* child = current_->FindChild(name); | 525 Node* child = current_->FindChild(name); |
518 if (child == NULL || child->kind() != LIST) { | 526 if (child == NULL || child->kind() != LIST) { |
519 google::protobuf::scoped_ptr<Node> node( | 527 google::protobuf::scoped_ptr<Node> node( |
520 new Node(name.ToString(), NULL, LIST, DataPiece::NullData(), false, | 528 new Node(name.ToString(), NULL, LIST, DataPiece::NullData(), false, |
521 child == NULL ? current_->path() : child->path(), | 529 child == NULL ? current_->path() : child->path(), |
522 field_scrub_callback_.get())); | 530 suppress_empty_list_, field_scrub_callback_.get())); |
523 child = node.get(); | 531 child = node.get(); |
524 current_->AddChild(node.release()); | 532 current_->AddChild(node.release()); |
525 } | 533 } |
526 child->set_is_placeholder(false); | 534 child->set_is_placeholder(false); |
527 | 535 |
528 stack_.push(current_); | 536 stack_.push(current_); |
529 current_ = child; | 537 current_ = child; |
530 return this; | 538 return this; |
531 } | 539 } |
532 | 540 |
533 void DefaultValueObjectWriter::WriteRoot() { | 541 void DefaultValueObjectWriter::WriteRoot() { |
534 root_->WriteTo(ow_); | 542 root_->WriteTo(ow_); |
535 root_.reset(NULL); | 543 root_.reset(NULL); |
536 current_ = NULL; | 544 current_ = NULL; |
537 } | 545 } |
538 | 546 |
539 DefaultValueObjectWriter* DefaultValueObjectWriter::EndList() { | 547 DefaultValueObjectWriter* DefaultValueObjectWriter::EndList() { |
540 if (stack_.empty()) { | 548 if (stack_.empty()) { |
541 WriteRoot(); | 549 WriteRoot(); |
542 return this; | 550 return this; |
543 } | 551 } |
544 current_ = stack_.top(); | 552 current_ = stack_.top(); |
545 stack_.pop(); | 553 stack_.pop(); |
546 return this; | 554 return this; |
547 } | 555 } |
548 | 556 |
549 void DefaultValueObjectWriter::RenderDataPiece(StringPiece name, | 557 void DefaultValueObjectWriter::RenderDataPiece(StringPiece name, |
550 const DataPiece& data) { | 558 const DataPiece& data) { |
551 MaybePopulateChildrenOfAny(current_); | 559 MaybePopulateChildrenOfAny(current_); |
552 util::StatusOr<string> data_string = data.ToString(); | |
553 if (current_->type() != NULL && current_->type()->name() == kAnyType && | 560 if (current_->type() != NULL && current_->type()->name() == kAnyType && |
554 name == "@type" && data_string.ok()) { | 561 name == "@type") { |
555 const string& string_value = data_string.ValueOrDie(); | 562 util::StatusOr<string> data_string = data.ToString(); |
556 // If the type of current_ is "Any" and its "@type" field is being set here, | 563 if (data_string.ok()) { |
557 // sets the type of current_ to be the type specified by the "@type". | 564 const string& string_value = data_string.ValueOrDie(); |
558 util::StatusOr<const google::protobuf::Type*> found_type = | 565 // If the type of current_ is "Any" and its "@type" field is being set |
559 typeinfo_->ResolveTypeUrl(string_value); | 566 // here, sets the type of current_ to be the type specified by the |
560 if (!found_type.ok()) { | 567 // "@type". |
561 GOOGLE_LOG(WARNING) << "Failed to resolve type '" << string_value << "'."; | 568 util::StatusOr<const google::protobuf::Type*> found_type = |
562 } else { | 569 typeinfo_->ResolveTypeUrl(string_value); |
563 current_->set_type(found_type.ValueOrDie()); | 570 if (!found_type.ok()) { |
564 } | 571 GOOGLE_LOG(WARNING) << "Failed to resolve type '" << string_value << "'.
"; |
565 current_->set_is_any(true); | 572 } else { |
566 // If the "@type" field is placed after other fields, we should populate | 573 current_->set_type(found_type.ValueOrDie()); |
567 // other children of primitive type now. Otherwise, we should wait until the | 574 } |
568 // first value field is rendered before we populate the children, because | 575 current_->set_is_any(true); |
569 // the "value" field of a Any message could be omitted. | 576 // If the "@type" field is placed after other fields, we should populate |
570 if (current_->number_of_children() > 1 && current_->type() != NULL) { | 577 // other children of primitive type now. Otherwise, we should wait until |
571 current_->PopulateChildren(typeinfo_); | 578 // the first value field is rendered before we populate the children, |
| 579 // because the "value" field of a Any message could be omitted. |
| 580 if (current_->number_of_children() > 1 && current_->type() != NULL) { |
| 581 current_->PopulateChildren(typeinfo_); |
| 582 } |
572 } | 583 } |
573 } | 584 } |
574 Node* child = current_->FindChild(name); | 585 Node* child = current_->FindChild(name); |
575 if (child == NULL || child->kind() != PRIMITIVE) { | 586 if (child == NULL || child->kind() != PRIMITIVE) { |
576 // No children are found, creates a new child. | 587 // No children are found, creates a new child. |
577 google::protobuf::scoped_ptr<Node> node( | 588 google::protobuf::scoped_ptr<Node> node( |
578 new Node(name.ToString(), NULL, PRIMITIVE, data, false, | 589 new Node(name.ToString(), NULL, PRIMITIVE, data, false, |
579 child == NULL ? current_->path() : child->path(), | 590 child == NULL ? current_->path() : child->path(), |
580 field_scrub_callback_.get())); | 591 suppress_empty_list_, field_scrub_callback_.get())); |
581 child = node.get(); | |
582 current_->AddChild(node.release()); | 592 current_->AddChild(node.release()); |
583 } else { | 593 } else { |
584 child->set_data(data); | 594 child->set_data(data); |
585 } | 595 } |
586 } | 596 } |
587 | 597 |
588 } // namespace converter | 598 } // namespace converter |
589 } // namespace util | 599 } // namespace util |
590 } // namespace protobuf | 600 } // namespace protobuf |
591 } // namespace google | 601 } // namespace google |
OLD | NEW |