serializer.js 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  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 Base class for all Protocol Buffer 2 serializers.
  16. */
  17. goog.provide('goog.proto2.Serializer');
  18. goog.require('goog.asserts');
  19. goog.require('goog.proto2.FieldDescriptor');
  20. goog.require('goog.proto2.Message');
  21. /**
  22. * Abstract base class for PB2 serializers. A serializer is a class which
  23. * implements the serialization and deserialization of a Protocol Buffer Message
  24. * to/from a specific format.
  25. *
  26. * @constructor
  27. */
  28. goog.proto2.Serializer = function() {};
  29. /**
  30. * @define {boolean} Whether to decode and convert symbolic enum values to
  31. * actual enum values or leave them as strings.
  32. */
  33. goog.define('goog.proto2.Serializer.DECODE_SYMBOLIC_ENUMS', false);
  34. /**
  35. * Serializes a message to the expected format.
  36. *
  37. * @param {goog.proto2.Message} message The message to be serialized.
  38. *
  39. * @return {*} The serialized form of the message.
  40. */
  41. goog.proto2.Serializer.prototype.serialize = goog.abstractMethod;
  42. /**
  43. * Returns the serialized form of the given value for the given field if the
  44. * field is a Message or Group and returns the value unchanged otherwise, except
  45. * for Infinity, -Infinity and NaN numerical values which are converted to
  46. * string representation.
  47. *
  48. * @param {goog.proto2.FieldDescriptor} field The field from which this
  49. * value came.
  50. *
  51. * @param {*} value The value of the field.
  52. *
  53. * @return {*} The value.
  54. * @protected
  55. */
  56. goog.proto2.Serializer.prototype.getSerializedValue = function(field, value) {
  57. if (field.isCompositeType()) {
  58. return this.serialize(/** @type {goog.proto2.Message} */ (value));
  59. } else if (goog.isNumber(value) && !isFinite(value)) {
  60. return value.toString();
  61. } else {
  62. return value;
  63. }
  64. };
  65. /**
  66. * Deserializes a message from the expected format.
  67. *
  68. * @param {goog.proto2.Descriptor} descriptor The descriptor of the message
  69. * to be created.
  70. * @param {*} data The data of the message.
  71. *
  72. * @return {!goog.proto2.Message} The message created.
  73. */
  74. goog.proto2.Serializer.prototype.deserialize = function(descriptor, data) {
  75. var message = descriptor.createMessageInstance();
  76. this.deserializeTo(message, data);
  77. goog.asserts.assert(message instanceof goog.proto2.Message);
  78. return message;
  79. };
  80. /**
  81. * Deserializes a message from the expected format and places the
  82. * data in the message.
  83. *
  84. * @param {goog.proto2.Message} message The message in which to
  85. * place the information.
  86. * @param {*} data The data of the message.
  87. */
  88. goog.proto2.Serializer.prototype.deserializeTo = goog.abstractMethod;
  89. /**
  90. * Returns the deserialized form of the given value for the given field if the
  91. * field is a Message or Group and returns the value, converted or unchanged,
  92. * for primitive field types otherwise.
  93. *
  94. * @param {goog.proto2.FieldDescriptor} field The field from which this
  95. * value came.
  96. *
  97. * @param {*} value The value of the field.
  98. *
  99. * @return {*} The value.
  100. * @protected
  101. */
  102. goog.proto2.Serializer.prototype.getDeserializedValue = function(field, value) {
  103. // Composite types are deserialized recursively.
  104. if (field.isCompositeType()) {
  105. if (value instanceof goog.proto2.Message) {
  106. return value;
  107. }
  108. return this.deserialize(field.getFieldMessageType(), value);
  109. }
  110. // Decode enum values.
  111. if (field.getFieldType() == goog.proto2.FieldDescriptor.FieldType.ENUM) {
  112. // If it's a string, get enum value by name.
  113. // NB: In order this feature to work, property renaming should be turned off
  114. // for the respective enums.
  115. if (goog.proto2.Serializer.DECODE_SYMBOLIC_ENUMS && goog.isString(value)) {
  116. // enumType is a regular Javascript enum as defined in field's metadata.
  117. var enumType = field.getNativeType();
  118. if (enumType.hasOwnProperty(value)) {
  119. return enumType[value];
  120. }
  121. }
  122. // If it's a string containing a positive integer, this looks like a viable
  123. // enum int value. Return as numeric.
  124. if (goog.isString(value) &&
  125. goog.proto2.Serializer.INTEGER_REGEX.test(value)) {
  126. var numeric = Number(value);
  127. if (numeric > 0) {
  128. return numeric;
  129. }
  130. }
  131. // Return unknown values as is for backward compatibility.
  132. return value;
  133. }
  134. // Return the raw value if the field does not allow the JSON input to be
  135. // converted.
  136. if (!field.deserializationConversionPermitted()) {
  137. return value;
  138. }
  139. // Convert to native type of field. Return the converted value or fall
  140. // through to return the raw value. The JSON encoding of int64 value 123
  141. // might be either the number 123 or the string "123". The field native type
  142. // could be either Number or String (depending on field options in the .proto
  143. // file). All four combinations should work correctly.
  144. var nativeType = field.getNativeType();
  145. if (nativeType === String) {
  146. // JSON numbers can be converted to strings.
  147. if (goog.isNumber(value)) {
  148. return String(value);
  149. }
  150. } else if (nativeType === Number) {
  151. // JSON strings are sometimes used for large integer numeric values, as well
  152. // as Infinity, -Infinity and NaN.
  153. if (goog.isString(value)) {
  154. // Handle +/- Infinity and NaN values.
  155. if (value === 'Infinity' || value === '-Infinity' || value === 'NaN') {
  156. return Number(value);
  157. }
  158. // Validate the string. If the string is not an integral number, we would
  159. // rather have an assertion or error in the caller than a mysterious NaN
  160. // value.
  161. if (goog.proto2.Serializer.INTEGER_REGEX.test(value)) {
  162. return Number(value);
  163. }
  164. }
  165. }
  166. return value;
  167. };
  168. /** @const {!RegExp} */
  169. goog.proto2.Serializer.INTEGER_REGEX = /^-?[0-9]+$/;