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