objectserializer.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. // Copyright 2008 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. /**
  15. * @fileoverview Protocol Buffer 2 Serializer which serializes messages
  16. * into anonymous, simplified JSON objects.
  17. *
  18. */
  19. goog.provide('goog.proto2.ObjectSerializer');
  20. goog.require('goog.asserts');
  21. goog.require('goog.proto2.FieldDescriptor');
  22. goog.require('goog.proto2.Serializer');
  23. goog.require('goog.string');
  24. /**
  25. * ObjectSerializer, a serializer which turns Messages into simplified
  26. * ECMAScript objects.
  27. *
  28. * @param {goog.proto2.ObjectSerializer.KeyOption=} opt_keyOption If specified,
  29. * which key option to use when serializing/deserializing.
  30. * @param {boolean=} opt_serializeBooleanAsNumber If specified and true, the
  31. * serializer will convert boolean values to 0/1 representation.
  32. * @constructor
  33. * @extends {goog.proto2.Serializer}
  34. */
  35. goog.proto2.ObjectSerializer = function(
  36. opt_keyOption, opt_serializeBooleanAsNumber) {
  37. this.keyOption_ = opt_keyOption;
  38. this.serializeBooleanAsNumber_ = opt_serializeBooleanAsNumber;
  39. };
  40. goog.inherits(goog.proto2.ObjectSerializer, goog.proto2.Serializer);
  41. /**
  42. * An enumeration of the options for how to emit the keys in
  43. * the generated simplified object.
  44. *
  45. * @enum {number}
  46. */
  47. goog.proto2.ObjectSerializer.KeyOption = {
  48. /**
  49. * Use the tag of the field as the key (default)
  50. */
  51. TAG: 0,
  52. /**
  53. * Use the name of the field as the key. Unknown fields
  54. * will still use their tags as keys.
  55. */
  56. NAME: 1
  57. };
  58. /**
  59. * Serializes a message to an object.
  60. *
  61. * @param {goog.proto2.Message} message The message to be serialized.
  62. * @return {!Object} The serialized form of the message.
  63. * @override
  64. */
  65. goog.proto2.ObjectSerializer.prototype.serialize = function(message) {
  66. var descriptor = message.getDescriptor();
  67. var fields = descriptor.getFields();
  68. var objectValue = {};
  69. // Add the defined fields, recursively.
  70. for (var i = 0; i < fields.length; i++) {
  71. var field = fields[i];
  72. var key = this.keyOption_ == goog.proto2.ObjectSerializer.KeyOption.NAME ?
  73. field.getName() :
  74. field.getTag();
  75. if (message.has(field)) {
  76. if (field.isRepeated()) {
  77. var array = [];
  78. objectValue[key] = array;
  79. for (var j = 0; j < message.countOf(field); j++) {
  80. array.push(this.getSerializedValue(field, message.get(field, j)));
  81. }
  82. } else {
  83. objectValue[key] = this.getSerializedValue(field, message.get(field));
  84. }
  85. }
  86. }
  87. // Add the unknown fields, if any.
  88. message.forEachUnknown(function(tag, value) { objectValue[tag] = value; });
  89. return objectValue;
  90. };
  91. /** @override */
  92. goog.proto2.ObjectSerializer.prototype.getSerializedValue = function(
  93. field, value) {
  94. // Handle the case where a boolean should be serialized as 0/1.
  95. // Some deserialization libraries, such as GWT, can use this notation.
  96. if (this.serializeBooleanAsNumber_ &&
  97. field.getFieldType() == goog.proto2.FieldDescriptor.FieldType.BOOL &&
  98. goog.isBoolean(value)) {
  99. return value ? 1 : 0;
  100. }
  101. return goog.proto2.ObjectSerializer.base(
  102. this, 'getSerializedValue', field, value);
  103. };
  104. /** @override */
  105. goog.proto2.ObjectSerializer.prototype.getDeserializedValue = function(
  106. field, value) {
  107. // Gracefully handle the case where a boolean is represented by 0/1.
  108. // Some serialization libraries, such as GWT, can use this notation.
  109. if (field.getFieldType() == goog.proto2.FieldDescriptor.FieldType.BOOL &&
  110. goog.isNumber(value)) {
  111. return Boolean(value);
  112. }
  113. return goog.proto2.ObjectSerializer.base(
  114. this, 'getDeserializedValue', field, value);
  115. };
  116. /**
  117. * Deserializes a message from an object and places the
  118. * data in the message.
  119. *
  120. * @param {goog.proto2.Message} message The message in which to
  121. * place the information.
  122. * @param {*} data The data of the message.
  123. * @override
  124. */
  125. goog.proto2.ObjectSerializer.prototype.deserializeTo = function(message, data) {
  126. var descriptor = message.getDescriptor();
  127. for (var key in data) {
  128. var field;
  129. var value = data[key];
  130. var isNumeric = goog.string.isNumeric(key);
  131. if (isNumeric) {
  132. field = descriptor.findFieldByTag(key);
  133. } else {
  134. // We must be in Key == NAME mode to lookup by name.
  135. goog.asserts.assert(
  136. this.keyOption_ == goog.proto2.ObjectSerializer.KeyOption.NAME,
  137. 'Key mode ' + this.keyOption_ + 'for key ' + key + ' is not ' +
  138. goog.proto2.ObjectSerializer.KeyOption.NAME);
  139. field = descriptor.findFieldByName(key);
  140. }
  141. if (field) {
  142. if (field.isRepeated()) {
  143. goog.asserts.assert(
  144. goog.isArray(value),
  145. 'Value for repeated field ' + field + ' must be an array.');
  146. for (var j = 0; j < value.length; j++) {
  147. message.add(field, this.getDeserializedValue(field, value[j]));
  148. }
  149. } else {
  150. goog.asserts.assert(
  151. !goog.isArray(value),
  152. 'Value for non-repeated field ' + field + ' must not be an array.');
  153. message.set(field, this.getDeserializedValue(field, value));
  154. }
  155. } else {
  156. if (isNumeric) {
  157. // We have an unknown field.
  158. message.setUnknown(Number(key), value);
  159. } else {
  160. // Named fields must be present.
  161. goog.asserts.fail('Failed to find field: ' + key);
  162. }
  163. }
  164. }
  165. };