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 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
56 using util::StatusOr; | 56 using util::StatusOr; |
57 | 57 |
58 | 58 |
59 ProtoStreamObjectWriter::ProtoStreamObjectWriter( | 59 ProtoStreamObjectWriter::ProtoStreamObjectWriter( |
60 TypeResolver* type_resolver, const google::protobuf::Type& type, | 60 TypeResolver* type_resolver, const google::protobuf::Type& type, |
61 strings::ByteSink* output, ErrorListener* listener, | 61 strings::ByteSink* output, ErrorListener* listener, |
62 const ProtoStreamObjectWriter::Options& options) | 62 const ProtoStreamObjectWriter::Options& options) |
63 : ProtoWriter(type_resolver, type, output, listener), | 63 : ProtoWriter(type_resolver, type, output, listener), |
64 master_type_(type), | 64 master_type_(type), |
65 current_(NULL), | 65 current_(NULL), |
66 options_(options) {} | 66 options_(options) { |
| 67 set_ignore_unknown_fields(options_.ignore_unknown_fields); |
| 68 set_use_lower_camel_for_enums(options_.use_lower_camel_for_enums); |
| 69 } |
67 | 70 |
68 ProtoStreamObjectWriter::ProtoStreamObjectWriter( | 71 ProtoStreamObjectWriter::ProtoStreamObjectWriter( |
69 const TypeInfo* typeinfo, const google::protobuf::Type& type, | 72 const TypeInfo* typeinfo, const google::protobuf::Type& type, |
70 strings::ByteSink* output, ErrorListener* listener) | 73 strings::ByteSink* output, ErrorListener* listener) |
71 : ProtoWriter(typeinfo, type, output, listener), | 74 : ProtoWriter(typeinfo, type, output, listener), |
72 master_type_(type), | 75 master_type_(type), |
73 current_(NULL), | 76 current_(NULL), |
74 options_(ProtoStreamObjectWriter::Options::Defaults()) {} | 77 options_(ProtoStreamObjectWriter::Options::Defaults()) {} |
75 | 78 |
76 ProtoStreamObjectWriter::~ProtoStreamObjectWriter() { | 79 ProtoStreamObjectWriter::~ProtoStreamObjectWriter() { |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
183 output_(&data_), | 186 output_(&data_), |
184 depth_(0), | 187 depth_(0), |
185 is_well_known_type_(false), | 188 is_well_known_type_(false), |
186 well_known_type_render_(NULL) {} | 189 well_known_type_render_(NULL) {} |
187 | 190 |
188 ProtoStreamObjectWriter::AnyWriter::~AnyWriter() {} | 191 ProtoStreamObjectWriter::AnyWriter::~AnyWriter() {} |
189 | 192 |
190 void ProtoStreamObjectWriter::AnyWriter::StartObject(StringPiece name) { | 193 void ProtoStreamObjectWriter::AnyWriter::StartObject(StringPiece name) { |
191 ++depth_; | 194 ++depth_; |
192 // If an object writer is absent, that means we have not called StartAny() | 195 // If an object writer is absent, that means we have not called StartAny() |
193 // before reaching here. This is an invalid state. StartAny() gets called | 196 // before reaching here, which happens when we have data before the "@type" |
194 // whenever we see an "@type" being rendered (see AnyWriter::RenderDataPiece). | 197 // field. |
195 if (ow_ == NULL) { | 198 if (ow_ == NULL) { |
196 // Make sure we are not already in an invalid state. This avoids making | 199 // Save data before the "@type" field for later replay. |
197 // multiple unnecessary InvalidValue calls. | 200 uninterpreted_events_.push_back(Event(Event::START_OBJECT, name)); |
198 if (!invalid_) { | |
199 parent_->InvalidValue("Any", | |
200 StrCat("Missing or invalid @type for any field in ", | |
201 parent_->master_type_.name())); | |
202 invalid_ = true; | |
203 } | |
204 } else if (is_well_known_type_ && depth_ == 1) { | 201 } else if (is_well_known_type_ && depth_ == 1) { |
205 // For well-known types, the only other field besides "@type" should be a | 202 // For well-known types, the only other field besides "@type" should be a |
206 // "value" field. | 203 // "value" field. |
207 if (name != "value" && !invalid_) { | 204 if (name != "value" && !invalid_) { |
208 parent_->InvalidValue("Any", | 205 parent_->InvalidValue("Any", |
209 "Expect a \"value\" field for well-known types."); | 206 "Expect a \"value\" field for well-known types."); |
210 invalid_ = true; | 207 invalid_ = true; |
211 } | 208 } |
212 ow_->StartObject(""); | 209 ow_->StartObject(""); |
213 } else { | 210 } else { |
214 // Forward the call to the child writer if: | 211 // Forward the call to the child writer if: |
215 // 1. the type is not a well-known type. | 212 // 1. the type is not a well-known type. |
216 // 2. or, we are in a nested Any, Struct, or Value object. | 213 // 2. or, we are in a nested Any, Struct, or Value object. |
217 ow_->StartObject(name); | 214 ow_->StartObject(name); |
218 } | 215 } |
219 } | 216 } |
220 | 217 |
221 bool ProtoStreamObjectWriter::AnyWriter::EndObject() { | 218 bool ProtoStreamObjectWriter::AnyWriter::EndObject() { |
222 --depth_; | 219 --depth_; |
223 // As long as depth_ >= 0, we know we haven't reached the end of Any. | 220 if (ow_ == NULL) { |
224 // Propagate these EndObject() calls to the contained ow_. For regular | 221 if (depth_ >= 0) { |
225 // message types, we propagate the end of Any as well. | 222 // Save data before the "@type" field for later replay. |
226 if (ow_ != NULL && (depth_ >= 0 || !is_well_known_type_)) { | 223 uninterpreted_events_.push_back(Event(Event::END_OBJECT)); |
| 224 } |
| 225 } else if (depth_ >= 0 || !is_well_known_type_) { |
| 226 // As long as depth_ >= 0, we know we haven't reached the end of Any. |
| 227 // Propagate these EndObject() calls to the contained ow_. For regular |
| 228 // message types, we propagate the end of Any as well. |
227 ow_->EndObject(); | 229 ow_->EndObject(); |
228 } | 230 } |
229 // A negative depth_ implies that we have reached the end of Any | 231 // A negative depth_ implies that we have reached the end of Any |
230 // object. Now we write out its contents. | 232 // object. Now we write out its contents. |
231 if (depth_ < 0) { | 233 if (depth_ < 0) { |
232 WriteAny(); | 234 WriteAny(); |
233 return false; | 235 return false; |
234 } | 236 } |
235 return true; | 237 return true; |
236 } | 238 } |
237 | 239 |
238 void ProtoStreamObjectWriter::AnyWriter::StartList(StringPiece name) { | 240 void ProtoStreamObjectWriter::AnyWriter::StartList(StringPiece name) { |
239 ++depth_; | 241 ++depth_; |
240 // We expect ow_ to be present as this call only makes sense inside an Any. | |
241 if (ow_ == NULL) { | 242 if (ow_ == NULL) { |
242 if (!invalid_) { | 243 // Save data before the "@type" field for later replay. |
243 parent_->InvalidValue("Any", | 244 uninterpreted_events_.push_back(Event(Event::START_LIST, name)); |
244 StrCat("Missing or invalid @type for any field in ", | |
245 parent_->master_type_.name())); | |
246 invalid_ = true; | |
247 } | |
248 } else if (is_well_known_type_ && depth_ == 1) { | 245 } else if (is_well_known_type_ && depth_ == 1) { |
249 if (name != "value" && !invalid_) { | 246 if (name != "value" && !invalid_) { |
250 parent_->InvalidValue("Any", | 247 parent_->InvalidValue("Any", |
251 "Expect a \"value\" field for well-known types."); | 248 "Expect a \"value\" field for well-known types."); |
252 invalid_ = true; | 249 invalid_ = true; |
253 } | 250 } |
254 ow_->StartList(""); | 251 ow_->StartList(""); |
255 } else { | 252 } else { |
256 ow_->StartList(name); | 253 ow_->StartList(name); |
257 } | 254 } |
258 } | 255 } |
259 | 256 |
260 void ProtoStreamObjectWriter::AnyWriter::EndList() { | 257 void ProtoStreamObjectWriter::AnyWriter::EndList() { |
261 --depth_; | 258 --depth_; |
262 if (depth_ < 0) { | 259 if (depth_ < 0) { |
263 GOOGLE_LOG(DFATAL) << "Mismatched EndList found, should not be possible"; | 260 GOOGLE_LOG(DFATAL) << "Mismatched EndList found, should not be possible"; |
264 depth_ = 0; | 261 depth_ = 0; |
265 } | 262 } |
266 // We don't write an error on the close, only on the open | 263 if (ow_ == NULL) { |
267 if (ow_ != NULL) { | 264 // Save data before the "@type" field for later replay. |
| 265 uninterpreted_events_.push_back(Event(Event::END_LIST)); |
| 266 } else { |
268 ow_->EndList(); | 267 ow_->EndList(); |
269 } | 268 } |
270 } | 269 } |
271 | 270 |
272 void ProtoStreamObjectWriter::AnyWriter::RenderDataPiece( | 271 void ProtoStreamObjectWriter::AnyWriter::RenderDataPiece( |
273 StringPiece name, const DataPiece& value) { | 272 StringPiece name, const DataPiece& value) { |
274 // Start an Any only at depth_ 0. Other RenderDataPiece calls with "@type" | 273 // Start an Any only at depth_ 0. Other RenderDataPiece calls with "@type" |
275 // should go to the contained ow_ as they indicate nested Anys. | 274 // should go to the contained ow_ as they indicate nested Anys. |
276 if (depth_ == 0 && ow_ == NULL && name == "@type") { | 275 if (depth_ == 0 && ow_ == NULL && name == "@type") { |
277 StartAny(value); | 276 StartAny(value); |
278 } else if (ow_ == NULL) { | 277 } else if (ow_ == NULL) { |
279 if (!invalid_) { | 278 // Save data before the "@type" field. |
280 parent_->InvalidValue("Any", | 279 uninterpreted_events_.push_back(Event(name, value)); |
281 StrCat("Missing or invalid @type for any field in ", | |
282 parent_->master_type_.name())); | |
283 invalid_ = true; | |
284 } | |
285 } else if (depth_ == 0 && is_well_known_type_) { | 280 } else if (depth_ == 0 && is_well_known_type_) { |
286 if (name != "value" && !invalid_) { | 281 if (name != "value" && !invalid_) { |
287 parent_->InvalidValue("Any", | 282 parent_->InvalidValue("Any", |
288 "Expect a \"value\" field for well-known types."); | 283 "Expect a \"value\" field for well-known types."); |
289 invalid_ = true; | 284 invalid_ = true; |
290 } | 285 } |
291 if (well_known_type_render_ == NULL) { | 286 if (well_known_type_render_ == NULL) { |
292 // Only Any and Struct don't have a special type render but both of | 287 // Only Any and Struct don't have a special type render but both of |
293 // them expect a JSON object (i.e., a StartObject() call). | 288 // them expect a JSON object (i.e., a StartObject() call). |
294 if (!invalid_) { | 289 if (value.type() != DataPiece::TYPE_NULL && !invalid_) { |
295 parent_->InvalidValue("Any", "Expect a JSON object."); | 290 parent_->InvalidValue("Any", "Expect a JSON object."); |
296 invalid_ = true; | 291 invalid_ = true; |
297 } | 292 } |
298 } else { | 293 } else { |
299 ow_->ProtoWriter::StartObject(""); | 294 ow_->ProtoWriter::StartObject(""); |
300 Status status = (*well_known_type_render_)(ow_.get(), value); | 295 Status status = (*well_known_type_render_)(ow_.get(), value); |
301 if (!status.ok()) ow_->InvalidValue("Any", status.error_message()); | 296 if (!status.ok()) ow_->InvalidValue("Any", status.error_message()); |
302 ow_->ProtoWriter::EndObject(); | 297 ow_->ProtoWriter::EndObject(); |
303 } | 298 } |
304 } else { | 299 } else { |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
349 // example: | 344 // example: |
350 // { | 345 // { |
351 // "@type": "type.googleapis.com/google.protobuf.Value", | 346 // "@type": "type.googleapis.com/google.protobuf.Value", |
352 // "value": [1, 2, 3], | 347 // "value": [1, 2, 3], |
353 // } | 348 // } |
354 // With the above JSON representation, we will only call StartList() on the | 349 // With the above JSON representation, we will only call StartList() on the |
355 // contained ow_. | 350 // contained ow_. |
356 if (!is_well_known_type_) { | 351 if (!is_well_known_type_) { |
357 ow_->StartObject(""); | 352 ow_->StartObject(""); |
358 } | 353 } |
| 354 |
| 355 // Now we know the proto type and can interpret all data fields we gathered |
| 356 // before the "@type" field. |
| 357 for (int i = 0; i < uninterpreted_events_.size(); ++i) { |
| 358 uninterpreted_events_[i].Replay(this); |
| 359 } |
359 } | 360 } |
360 | 361 |
361 void ProtoStreamObjectWriter::AnyWriter::WriteAny() { | 362 void ProtoStreamObjectWriter::AnyWriter::WriteAny() { |
362 if (ow_ == NULL) { | 363 if (ow_ == NULL) { |
363 // If we had no object writer, we never got any content, so just return | 364 if (uninterpreted_events_.empty()) { |
364 // immediately, which is equivalent to writing an empty Any. | 365 // We never got any content, so just return immediately, which is |
365 return; | 366 // equivalent to writing an empty Any. |
| 367 return; |
| 368 } else { |
| 369 // There are uninterpreted data, but we never got a "@type" field. |
| 370 if (!invalid_) { |
| 371 parent_->InvalidValue("Any", StrCat("Missing @type for any field in ", |
| 372 parent_->master_type_.name())); |
| 373 invalid_ = true; |
| 374 } |
| 375 return; |
| 376 } |
366 } | 377 } |
367 // Render the type_url and value fields directly to the stream. | 378 // Render the type_url and value fields directly to the stream. |
368 // type_url has tag 1 and value has tag 2. | 379 // type_url has tag 1 and value has tag 2. |
369 WireFormatLite::WriteString(1, type_url_, parent_->stream()); | 380 WireFormatLite::WriteString(1, type_url_, parent_->stream()); |
370 if (!data_.empty()) { | 381 if (!data_.empty()) { |
371 WireFormatLite::WriteBytes(2, data_, parent_->stream()); | 382 WireFormatLite::WriteBytes(2, data_, parent_->stream()); |
372 } | 383 } |
373 } | 384 } |
374 | 385 |
| 386 void ProtoStreamObjectWriter::AnyWriter::Event::Replay( |
| 387 AnyWriter* writer) const { |
| 388 switch (type_) { |
| 389 case START_OBJECT: |
| 390 writer->StartObject(name_); |
| 391 break; |
| 392 case END_OBJECT: |
| 393 writer->EndObject(); |
| 394 break; |
| 395 case START_LIST: |
| 396 writer->StartList(name_); |
| 397 break; |
| 398 case END_LIST: |
| 399 writer->EndList(); |
| 400 break; |
| 401 case RENDER_DATA_PIECE: |
| 402 writer->RenderDataPiece(name_, value_); |
| 403 break; |
| 404 } |
| 405 } |
| 406 |
| 407 void ProtoStreamObjectWriter::AnyWriter::Event::DeepCopy() { |
| 408 // DataPiece only contains a string reference. To make sure the referenced |
| 409 // string value stays valid, we make a copy of the string value and update |
| 410 // DataPiece to reference our own copy. |
| 411 if (value_.type() == DataPiece::TYPE_STRING) { |
| 412 value_.str().AppendToString(&value_storage_); |
| 413 value_ = DataPiece(value_storage_, value_.use_strict_base64_decoding()); |
| 414 } else if (value_.type() == DataPiece::TYPE_BYTES) { |
| 415 value_storage_ = value_.ToBytes().ValueOrDie(); |
| 416 value_ = |
| 417 DataPiece(value_storage_, true, value_.use_strict_base64_decoding()); |
| 418 } |
| 419 } |
| 420 |
375 ProtoStreamObjectWriter::Item::Item(ProtoStreamObjectWriter* enclosing, | 421 ProtoStreamObjectWriter::Item::Item(ProtoStreamObjectWriter* enclosing, |
376 ItemType item_type, bool is_placeholder, | 422 ItemType item_type, bool is_placeholder, |
377 bool is_list) | 423 bool is_list) |
378 : BaseElement(NULL), | 424 : BaseElement(NULL), |
379 ow_(enclosing), | 425 ow_(enclosing), |
380 any_(), | 426 any_(), |
381 item_type_(item_type), | 427 item_type_(item_type), |
382 is_placeholder_(is_placeholder), | 428 is_placeholder_(is_placeholder), |
383 is_list_(is_list) { | 429 is_list_(is_list) { |
384 if (item_type_ == ANY) { | 430 if (item_type_ == ANY) { |
385 any_.reset(new AnyWriter(ow_)); | 431 any_.reset(new AnyWriter(ow_)); |
386 } | 432 } |
| 433 if (item_type == MAP) { |
| 434 map_keys_.reset(new hash_set<string>); |
| 435 } |
387 } | 436 } |
388 | 437 |
389 ProtoStreamObjectWriter::Item::Item(ProtoStreamObjectWriter::Item* parent, | 438 ProtoStreamObjectWriter::Item::Item(ProtoStreamObjectWriter::Item* parent, |
390 ItemType item_type, bool is_placeholder, | 439 ItemType item_type, bool is_placeholder, |
391 bool is_list) | 440 bool is_list) |
392 : BaseElement(parent), | 441 : BaseElement(parent), |
393 ow_(this->parent()->ow_), | 442 ow_(this->parent()->ow_), |
394 any_(), | 443 any_(), |
395 item_type_(item_type), | 444 item_type_(item_type), |
396 is_placeholder_(is_placeholder), | 445 is_placeholder_(is_placeholder), |
397 is_list_(is_list) { | 446 is_list_(is_list) { |
398 if (item_type == ANY) { | 447 if (item_type == ANY) { |
399 any_.reset(new AnyWriter(ow_)); | 448 any_.reset(new AnyWriter(ow_)); |
400 } | 449 } |
| 450 if (item_type == MAP) { |
| 451 map_keys_.reset(new hash_set<string>); |
| 452 } |
401 } | 453 } |
402 | 454 |
403 bool ProtoStreamObjectWriter::Item::InsertMapKeyIfNotPresent( | 455 bool ProtoStreamObjectWriter::Item::InsertMapKeyIfNotPresent( |
404 StringPiece map_key) { | 456 StringPiece map_key) { |
405 return InsertIfNotPresent(&map_keys_, map_key.ToString()); | 457 return InsertIfNotPresent(map_keys_.get(), map_key.ToString()); |
406 } | 458 } |
407 | 459 |
408 ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartObject( | 460 ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartObject( |
409 StringPiece name) { | 461 StringPiece name) { |
410 if (invalid_depth() > 0) { | 462 if (invalid_depth() > 0) { |
411 IncrementInvalidDepth(); | 463 IncrementInvalidDepth(); |
412 return this; | 464 return this; |
413 } | 465 } |
414 | 466 |
415 // Starting the root message. Create the root Item and return. | 467 // Starting the root message. Create the root Item and return. |
(...skipping 436 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
852 "Invalid struct data type. Only number, string, boolean or " | 904 "Invalid struct data type. Only number, string, boolean or " |
853 "null values are supported."); | 905 "null values are supported."); |
854 } | 906 } |
855 } | 907 } |
856 ow->ProtoWriter::RenderDataPiece(struct_field_name, data); | 908 ow->ProtoWriter::RenderDataPiece(struct_field_name, data); |
857 return Status::OK; | 909 return Status::OK; |
858 } | 910 } |
859 | 911 |
860 Status ProtoStreamObjectWriter::RenderTimestamp(ProtoStreamObjectWriter* ow, | 912 Status ProtoStreamObjectWriter::RenderTimestamp(ProtoStreamObjectWriter* ow, |
861 const DataPiece& data) { | 913 const DataPiece& data) { |
| 914 if (data.type() == DataPiece::TYPE_NULL) return Status::OK; |
862 if (data.type() != DataPiece::TYPE_STRING) { | 915 if (data.type() != DataPiece::TYPE_STRING) { |
863 return Status(INVALID_ARGUMENT, | 916 return Status(INVALID_ARGUMENT, |
864 StrCat("Invalid data type for timestamp, value is ", | 917 StrCat("Invalid data type for timestamp, value is ", |
865 data.ValueAsStringOrDefault(""))); | 918 data.ValueAsStringOrDefault(""))); |
866 } | 919 } |
867 | 920 |
868 StringPiece value(data.str()); | 921 StringPiece value(data.str()); |
869 | 922 |
870 int64 seconds; | 923 int64 seconds; |
871 int32 nanos; | 924 int32 nanos; |
(...skipping 10 matching lines...) Expand all Loading... |
882 | 935 |
883 static inline util::Status RenderOneFieldPath(ProtoStreamObjectWriter* ow, | 936 static inline util::Status RenderOneFieldPath(ProtoStreamObjectWriter* ow, |
884 StringPiece path) { | 937 StringPiece path) { |
885 ow->ProtoWriter::RenderDataPiece( | 938 ow->ProtoWriter::RenderDataPiece( |
886 "paths", DataPiece(ConvertFieldMaskPath(path, &ToSnakeCase), true)); | 939 "paths", DataPiece(ConvertFieldMaskPath(path, &ToSnakeCase), true)); |
887 return Status::OK; | 940 return Status::OK; |
888 } | 941 } |
889 | 942 |
890 Status ProtoStreamObjectWriter::RenderFieldMask(ProtoStreamObjectWriter* ow, | 943 Status ProtoStreamObjectWriter::RenderFieldMask(ProtoStreamObjectWriter* ow, |
891 const DataPiece& data) { | 944 const DataPiece& data) { |
| 945 if (data.type() == DataPiece::TYPE_NULL) return Status::OK; |
892 if (data.type() != DataPiece::TYPE_STRING) { | 946 if (data.type() != DataPiece::TYPE_STRING) { |
893 return Status(INVALID_ARGUMENT, | 947 return Status(INVALID_ARGUMENT, |
894 StrCat("Invalid data type for field mask, value is ", | 948 StrCat("Invalid data type for field mask, value is ", |
895 data.ValueAsStringOrDefault(""))); | 949 data.ValueAsStringOrDefault(""))); |
896 } | 950 } |
897 | 951 |
898 // TODO(tsun): figure out how to do proto descriptor based snake case | 952 // TODO(tsun): figure out how to do proto descriptor based snake case |
899 // conversions as much as possible. Because ToSnakeCase sometimes returns the | 953 // conversions as much as possible. Because ToSnakeCase sometimes returns the |
900 // wrong value. | 954 // wrong value. |
901 google::protobuf::scoped_ptr<ResultCallback1<util::Status, StringPiece> > call
back( | 955 google::protobuf::scoped_ptr<ResultCallback1<util::Status, StringPiece> > call
back( |
902 ::google::protobuf::internal::NewPermanentCallback(&RenderOneFieldPath, ow
)); | 956 NewPermanentCallback(&RenderOneFieldPath, ow)); |
903 return DecodeCompactFieldMaskPaths(data.str(), callback.get()); | 957 return DecodeCompactFieldMaskPaths(data.str(), callback.get()); |
904 } | 958 } |
905 | 959 |
906 Status ProtoStreamObjectWriter::RenderDuration(ProtoStreamObjectWriter* ow, | 960 Status ProtoStreamObjectWriter::RenderDuration(ProtoStreamObjectWriter* ow, |
907 const DataPiece& data) { | 961 const DataPiece& data) { |
| 962 if (data.type() == DataPiece::TYPE_NULL) return Status::OK; |
908 if (data.type() != DataPiece::TYPE_STRING) { | 963 if (data.type() != DataPiece::TYPE_STRING) { |
909 return Status(INVALID_ARGUMENT, | 964 return Status(INVALID_ARGUMENT, |
910 StrCat("Invalid data type for duration, value is ", | 965 StrCat("Invalid data type for duration, value is ", |
911 data.ValueAsStringOrDefault(""))); | 966 data.ValueAsStringOrDefault(""))); |
912 } | 967 } |
913 | 968 |
914 StringPiece value(data.str()); | 969 StringPiece value(data.str()); |
915 | 970 |
916 if (!value.ends_with("s")) { | 971 if (!value.ends_with("s")) { |
917 return Status(INVALID_ARGUMENT, | 972 return Status(INVALID_ARGUMENT, |
(...skipping 29 matching lines...) Expand all Loading... |
947 return Status(INVALID_ARGUMENT, "Duration value exceeds limits"); | 1002 return Status(INVALID_ARGUMENT, "Duration value exceeds limits"); |
948 } | 1003 } |
949 | 1004 |
950 ow->ProtoWriter::RenderDataPiece("seconds", DataPiece(seconds)); | 1005 ow->ProtoWriter::RenderDataPiece("seconds", DataPiece(seconds)); |
951 ow->ProtoWriter::RenderDataPiece("nanos", DataPiece(nanos)); | 1006 ow->ProtoWriter::RenderDataPiece("nanos", DataPiece(nanos)); |
952 return Status::OK; | 1007 return Status::OK; |
953 } | 1008 } |
954 | 1009 |
955 Status ProtoStreamObjectWriter::RenderWrapperType(ProtoStreamObjectWriter* ow, | 1010 Status ProtoStreamObjectWriter::RenderWrapperType(ProtoStreamObjectWriter* ow, |
956 const DataPiece& data) { | 1011 const DataPiece& data) { |
| 1012 if (data.type() == DataPiece::TYPE_NULL) return Status::OK; |
957 ow->ProtoWriter::RenderDataPiece("value", data); | 1013 ow->ProtoWriter::RenderDataPiece("value", data); |
958 return Status::OK; | 1014 return Status::OK; |
959 } | 1015 } |
960 | 1016 |
961 ProtoStreamObjectWriter* ProtoStreamObjectWriter::RenderDataPiece( | 1017 ProtoStreamObjectWriter* ProtoStreamObjectWriter::RenderDataPiece( |
962 StringPiece name, const DataPiece& data) { | 1018 StringPiece name, const DataPiece& data) { |
963 Status status; | 1019 Status status; |
964 if (invalid_depth() > 0) return this; | 1020 if (invalid_depth() > 0) return this; |
965 | 1021 |
966 if (current_ == NULL) { | 1022 if (current_ == NULL) { |
(...skipping 26 matching lines...) Expand all Loading... |
993 if (current_->IsMap()) { | 1049 if (current_->IsMap()) { |
994 if (!ValidMapKey(name)) return this; | 1050 if (!ValidMapKey(name)) return this; |
995 | 1051 |
996 // Render an item in repeated map list. | 1052 // Render an item in repeated map list. |
997 // { "key": "<name>", "value": | 1053 // { "key": "<name>", "value": |
998 Push("", Item::MESSAGE, false, false); | 1054 Push("", Item::MESSAGE, false, false); |
999 ProtoWriter::RenderDataPiece("key", | 1055 ProtoWriter::RenderDataPiece("key", |
1000 DataPiece(name, use_strict_base64_decoding())); | 1056 DataPiece(name, use_strict_base64_decoding())); |
1001 field = Lookup("value"); | 1057 field = Lookup("value"); |
1002 if (field == NULL) { | 1058 if (field == NULL) { |
| 1059 Pop(); |
1003 GOOGLE_LOG(DFATAL) << "Map does not have a value field."; | 1060 GOOGLE_LOG(DFATAL) << "Map does not have a value field."; |
1004 return this; | 1061 return this; |
1005 } | 1062 } |
1006 | 1063 |
1007 const TypeRenderer* type_renderer = FindTypeRenderer(field->type_url()); | 1064 const TypeRenderer* type_renderer = FindTypeRenderer(field->type_url()); |
1008 if (type_renderer != NULL) { | 1065 if (type_renderer != NULL) { |
1009 // Map's value type is a special type. Render it like a message: | 1066 // Map's value type is a special type. Render it like a message: |
1010 // "value": { | 1067 // "value": { |
1011 // ... Render special type ... | 1068 // ... Render special type ... |
1012 // } | 1069 // } |
(...skipping 20 matching lines...) Expand all Loading... |
1033 Pop(); | 1090 Pop(); |
1034 return this; | 1091 return this; |
1035 } | 1092 } |
1036 | 1093 |
1037 field = Lookup(name); | 1094 field = Lookup(name); |
1038 if (field == NULL) return this; | 1095 if (field == NULL) return this; |
1039 | 1096 |
1040 // Check if the field is of special type. Render it accordingly if so. | 1097 // Check if the field is of special type. Render it accordingly if so. |
1041 const TypeRenderer* type_renderer = FindTypeRenderer(field->type_url()); | 1098 const TypeRenderer* type_renderer = FindTypeRenderer(field->type_url()); |
1042 if (type_renderer != NULL) { | 1099 if (type_renderer != NULL) { |
1043 Push(name, Item::MESSAGE, false, false); | 1100 // Pass through null value only for google.protobuf.Value. For other |
1044 status = (*type_renderer)(this, data); | 1101 // types we ignore null value just like for regular field types. |
1045 if (!status.ok()) { | 1102 if (data.type() != DataPiece::TYPE_NULL || |
1046 InvalidValue(field->type_url(), | 1103 field->type_url() == kStructValueTypeUrl) { |
1047 StrCat("Field '", name, "', ", status.error_message())); | 1104 Push(name, Item::MESSAGE, false, false); |
| 1105 status = (*type_renderer)(this, data); |
| 1106 if (!status.ok()) { |
| 1107 InvalidValue(field->type_url(), |
| 1108 StrCat("Field '", name, "', ", status.error_message())); |
| 1109 } |
| 1110 Pop(); |
1048 } | 1111 } |
1049 Pop(); | |
1050 return this; | 1112 return this; |
1051 } | 1113 } |
1052 | 1114 |
1053 // If we are rendering explicit null values and the backend proto field is | 1115 // If we are rendering explicit null values and the backend proto field is |
1054 // not of the google.protobuf.NullType type, we do nothing. | 1116 // not of the google.protobuf.NullType type, we do nothing. |
1055 if (data.type() == DataPiece::TYPE_NULL && | 1117 if (data.type() == DataPiece::TYPE_NULL && |
1056 field->type_url() != kStructNullValueTypeUrl) { | 1118 field->type_url() != kStructNullValueTypeUrl) { |
1057 return this; | 1119 return this; |
1058 } | 1120 } |
1059 | 1121 |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1171 field.kind() != google::protobuf::Field_Kind_TYPE_MESSAGE || | 1233 field.kind() != google::protobuf::Field_Kind_TYPE_MESSAGE || |
1172 field.cardinality() != | 1234 field.cardinality() != |
1173 google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) { | 1235 google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) { |
1174 return false; | 1236 return false; |
1175 } | 1237 } |
1176 const google::protobuf::Type* field_type = | 1238 const google::protobuf::Type* field_type = |
1177 typeinfo()->GetTypeByTypeUrl(field.type_url()); | 1239 typeinfo()->GetTypeByTypeUrl(field.type_url()); |
1178 | 1240 |
1179 // TODO(xiaofeng): Unify option names. | 1241 // TODO(xiaofeng): Unify option names. |
1180 return GetBoolOptionOrDefault(field_type->options(), | 1242 return GetBoolOptionOrDefault(field_type->options(), |
1181 "google.protobuf.MessageOptions.map_entry", fals
e) || | 1243 "google.protobuf.MessageOptions.map_entry", |
1182 GetBoolOptionOrDefault(field_type->options(), "map_entry", false); | 1244 false) || |
| 1245 GetBoolOptionOrDefault(field_type->options(), "map_entry", false) || |
| 1246 GetBoolOptionOrDefault(field_type->options(), |
| 1247 "proto2.MessageOptions.map_entry", false); |
1183 } | 1248 } |
1184 | 1249 |
1185 bool ProtoStreamObjectWriter::IsAny(const google::protobuf::Field& field) { | 1250 bool ProtoStreamObjectWriter::IsAny(const google::protobuf::Field& field) { |
1186 return GetTypeWithoutUrl(field.type_url()) == kAnyType; | 1251 return GetTypeWithoutUrl(field.type_url()) == kAnyType; |
1187 } | 1252 } |
1188 | 1253 |
1189 bool ProtoStreamObjectWriter::IsStruct(const google::protobuf::Field& field) { | 1254 bool ProtoStreamObjectWriter::IsStruct(const google::protobuf::Field& field) { |
1190 return GetTypeWithoutUrl(field.type_url()) == kStructType; | 1255 return GetTypeWithoutUrl(field.type_url()) == kStructType; |
1191 } | 1256 } |
1192 | 1257 |
1193 bool ProtoStreamObjectWriter::IsStructValue( | 1258 bool ProtoStreamObjectWriter::IsStructValue( |
1194 const google::protobuf::Field& field) { | 1259 const google::protobuf::Field& field) { |
1195 return GetTypeWithoutUrl(field.type_url()) == kStructValueType; | 1260 return GetTypeWithoutUrl(field.type_url()) == kStructValueType; |
1196 } | 1261 } |
1197 | 1262 |
1198 bool ProtoStreamObjectWriter::IsStructListValue( | 1263 bool ProtoStreamObjectWriter::IsStructListValue( |
1199 const google::protobuf::Field& field) { | 1264 const google::protobuf::Field& field) { |
1200 return GetTypeWithoutUrl(field.type_url()) == kStructListValueType; | 1265 return GetTypeWithoutUrl(field.type_url()) == kStructListValueType; |
1201 } | 1266 } |
1202 | 1267 |
1203 } // namespace converter | 1268 } // namespace converter |
1204 } // namespace util | 1269 } // namespace util |
1205 } // namespace protobuf | 1270 } // namespace protobuf |
1206 } // namespace google | 1271 } // namespace google |
| 1272 |
OLD | NEW |