| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of dart.convert; | 5 part of dart.convert; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * Error thrown by JSON serialization if an object cannot be serialized. | 8 * Error thrown by JSON serialization if an object cannot be serialized. |
| 9 * | 9 * |
| 10 * The [unsupportedObject] field holds that object that failed to be serialized. | 10 * The [unsupportedObject] field holds that object that failed to be serialized. |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 83 * property that has been parsed during decoding. The `key` argument is either | 83 * property that has been parsed during decoding. The `key` argument is either |
| 84 * the integer list index for a list property, the map string for object | 84 * the integer list index for a list property, the map string for object |
| 85 * properties, or `null` for the final result. | 85 * properties, or `null` for the final result. |
| 86 * | 86 * |
| 87 * The default [reviver] (when not provided) is the identity function. | 87 * The default [reviver] (when not provided) is the identity function. |
| 88 */ | 88 */ |
| 89 Object decode(String str, {reviver(var key, var value)}) { | 89 Object decode(String str, {reviver(var key, var value)}) { |
| 90 return new JsonDecoder(reviver).convert(str); | 90 return new JsonDecoder(reviver).convert(str); |
| 91 } | 91 } |
| 92 | 92 |
| 93 /** |
| 94 * Converts [value] to a JSON string. |
| 95 * |
| 96 * If value contains objects that are not directly encodable to a JSON |
| 97 * string (a value that is not a number, boolean, string, null, list or a map |
| 98 * with string keys), the [toEncodable] function is used to convert it to an |
| 99 * object that must be directly encodable. |
| 100 * |
| 101 * If [toEncodable] is omitted, it defaults to calling `.toJson()` on the |
| 102 * unencodable object. |
| 103 */ |
| 104 Object encode(Object value, {toEncodable(var object)}) { |
| 105 return new JsonEncoder(toEncodable).convert(value); |
| 106 } |
| 107 |
| 93 JsonEncoder get encoder => new JsonEncoder(); | 108 JsonEncoder get encoder => new JsonEncoder(); |
| 94 JsonDecoder get decoder => new JsonDecoder(null); | 109 JsonDecoder get decoder => new JsonDecoder(null); |
| 95 } | 110 } |
| 96 | 111 |
| 97 typedef _Reviver(var key, var value); | 112 typedef _Reviver(var key, var value); |
| 98 | 113 |
| 99 class _ReviverJsonCodec extends JsonCodec { | 114 class _ReviverJsonCodec extends JsonCodec { |
| 100 final _Reviver _reviver; | 115 final _Reviver _reviver; |
| 101 _ReviverJsonCodec(this._reviver); | 116 _ReviverJsonCodec(this._reviver); |
| 102 | 117 |
| 103 Object decode(String str, {reviver(var key, var value)}) { | 118 Object decode(String str, {reviver(var key, var value)}) { |
| 104 if (reviver == null) reviver = _reviver; | 119 if (reviver == null) reviver = _reviver; |
| 105 return new JsonDecoder(reviver).convert(str); | 120 return new JsonDecoder(reviver).convert(str); |
| 106 } | 121 } |
| 107 | 122 |
| 108 JsonDecoder get decoder => new JsonDecoder(_reviver); | 123 JsonDecoder get decoder => new JsonDecoder(_reviver); |
| 109 } | 124 } |
| 110 | 125 |
| 111 /** | 126 /** |
| 112 * This class converts JSON objects to strings. | 127 * This class converts JSON objects to strings. |
| 113 */ | 128 */ |
| 114 class JsonEncoder extends Converter<Object, String> { | 129 class JsonEncoder extends Converter<Object, String> { |
| 115 JsonEncoder(); | 130 final _toEncodableFunction; |
| 131 |
| 132 /** |
| 133 * Creates a JSON encoder. |
| 134 * |
| 135 * The JSON encoder handles numbers, strings, booleans, null, lists and |
| 136 * maps directly. |
| 137 * |
| 138 * Any other object is attempted converted by [toEncodable] to an |
| 139 * object that is of one of the convertible types. |
| 140 * |
| 141 * If [toEncodable] is omitted, it defaults to calling `.toJson()` on |
| 142 * the object. |
| 143 */ |
| 144 JsonEncoder([Object toEncodable(Object nonSerializable)]) |
| 145 : this._toEncodableFunction = toEncodable; |
| 116 | 146 |
| 117 /** | 147 /** |
| 118 * Converts the given object [o] to its JSON representation. | 148 * Converts the given object [o] to its JSON representation. |
| 119 * | 149 * |
| 120 * Directly serializable values are [num], [String], [bool], and [Null], as | 150 * Directly serializable values are [num], [String], [bool], and [Null], as |
| 121 * well as some [List] and [Map] values. | 151 * well as some [List] and [Map] values. |
| 122 * For [List], the elements must all be serializable. | 152 * For [List], the elements must all be serializable. |
| 123 * For [Map], the keys must be [String] and the values must be serializable. | 153 * For [Map], the keys must be [String] and the values must be serializable. |
| 124 * | 154 * |
| 125 * If a value is any other type is attempted serialized, a "toJson()" method | 155 * If a value is any other type is attempted serialized, the conversion |
| 126 * is invoked on the object and the result, which must be a directly | 156 * function provided in the constructor is invoked with the object as argument |
| 127 * serializable value, is serialized instead of the original value. | 157 * and the result, which must be a directly serializable value, |
| 158 * is serialized instead of the original value. |
| 128 * | 159 * |
| 129 * If the object does not support this method, throws, or returns a | 160 * If the conversion throws, or returns a value that is not directly |
| 130 * value that is not directly serializable, a [JsonUnsupportedObjectError] | 161 * serializable, a [JsonUnsupportedObjectError] exception is thrown. |
| 131 * exception is thrown. If the call throws (including the case where there | 162 * If the call throws, the error is caught and stored in the |
| 132 * is no nullary "toJson" method, the error is caught and stored in the | |
| 133 * [JsonUnsupportedObjectError]'s [:cause:] field. | 163 * [JsonUnsupportedObjectError]'s [:cause:] field. |
| 134 * | 164 * |
| 135 * If a [List] or [Map] contains a reference to itself, directly or through | 165 * If a [List] or [Map] contains a reference to itself, directly or through |
| 136 * other lists or maps, it cannot be serialized and a [JsonCyclicError] is | 166 * other lists or maps, it cannot be serialized and a [JsonCyclicError] is |
| 137 * thrown. | 167 * thrown. |
| 138 * | 168 * |
| 139 * Json Objects should not change during serialization. | 169 * Json Objects should not change during serialization. |
| 140 * If an object is serialized more than once, [stringify] is allowed to cache | 170 * If an object is serialized more than once, [stringify] is allowed to cache |
| 141 * the JSON text for it. I.e., if an object changes after it is first | 171 * the JSON text for it. I.e., if an object changes after it is first |
| 142 * serialized, the new values may or may not be reflected in the result. | 172 * serialized, the new values may or may not be reflected in the result. |
| 143 */ | 173 */ |
| 144 String convert(Object o) => OLD_JSON_LIB.stringify(o); | 174 String convert(Object o) => OLD_JSON_LIB.stringify(o, _toEncodableFunction); |
| 145 | 175 |
| 146 /** | 176 /** |
| 147 * Starts a chunked conversion. | 177 * Starts a chunked conversion. |
| 148 * | 178 * |
| 149 * The converter works more efficiently if the given [sink] is a | 179 * The converter works more efficiently if the given [sink] is a |
| 150 * [StringConversionSink]. | 180 * [StringConversionSink]. |
| 151 * | 181 * |
| 152 * Returns a chunked-conversion sink that accepts at most one object. It is | 182 * Returns a chunked-conversion sink that accepts at most one object. It is |
| 153 * an error to invoke `add` more than once on the returned sink. | 183 * an error to invoke `add` more than once on the returned sink. |
| 154 */ | 184 */ |
| 155 ChunkedConversionSink<Object> startChunkedConversion( | 185 ChunkedConversionSink<Object> startChunkedConversion( |
| 156 ChunkedConversionSink<String> sink) { | 186 ChunkedConversionSink<String> sink) { |
| 157 if (sink is! StringConversionSink) { | 187 if (sink is! StringConversionSink) { |
| 158 sink = new StringConversionSink.from(sink); | 188 sink = new StringConversionSink.from(sink); |
| 159 } | 189 } |
| 160 return new _JsonEncoderSink(sink); | 190 return new _JsonEncoderSink(sink, _toEncodableFunction); |
| 161 } | 191 } |
| 162 | 192 |
| 163 // Override the base-classes bind, to provide a better type. | 193 // Override the base-classes bind, to provide a better type. |
| 164 Stream<String> bind(Stream<Object> stream) => super.bind(stream); | 194 Stream<String> bind(Stream<Object> stream) => super.bind(stream); |
| 165 } | 195 } |
| 166 | 196 |
| 167 /** | 197 /** |
| 168 * Implements the chunked conversion from object to its JSON representation. | 198 * Implements the chunked conversion from object to its JSON representation. |
| 169 * | 199 * |
| 170 * The sink only accepts one value, but will produce output in a chunked way. | 200 * The sink only accepts one value, but will produce output in a chunked way. |
| 171 */ | 201 */ |
| 172 class _JsonEncoderSink extends ChunkedConversionSink<Object> { | 202 class _JsonEncoderSink extends ChunkedConversionSink<Object> { |
| 203 final Function _toEncodableFunction; |
| 173 final StringConversionSink _sink; | 204 final StringConversionSink _sink; |
| 174 bool _isDone = false; | 205 bool _isDone = false; |
| 175 | 206 |
| 176 _JsonEncoderSink(this._sink); | 207 _JsonEncoderSink(this._sink, this._toEncodableFunction); |
| 177 | 208 |
| 178 /** | 209 /** |
| 179 * Encodes the given object [o]. | 210 * Encodes the given object [o]. |
| 180 * | 211 * |
| 181 * It is an error to invoke this method more than once on any instance. While | 212 * It is an error to invoke this method more than once on any instance. While |
| 182 * this makes the input effectly non-chunked the output will be generated in | 213 * this makes the input effectly non-chunked the output will be generated in |
| 183 * a chunked way. | 214 * a chunked way. |
| 184 */ | 215 */ |
| 185 void add(Object o) { | 216 void add(Object o) { |
| 186 if (_isDone) { | 217 if (_isDone) { |
| 187 throw new StateError("Only one call to add allowed"); | 218 throw new StateError("Only one call to add allowed"); |
| 188 } | 219 } |
| 189 _isDone = true; | 220 _isDone = true; |
| 190 ClosableStringSink stringSink = _sink.asStringSink(); | 221 ClosableStringSink stringSink = _sink.asStringSink(); |
| 191 OLD_JSON_LIB.printOn(o, stringSink); | 222 OLD_JSON_LIB.printOn(o, stringSink, _toEncodableFunction); |
| 192 stringSink.close(); | 223 stringSink.close(); |
| 193 } | 224 } |
| 194 | 225 |
| 195 void close() { /* do nothing */ } | 226 void close() { /* do nothing */ } |
| 196 } | 227 } |
| 197 | 228 |
| 198 /** | 229 /** |
| 199 * This class parses JSON strings and builds the corresponding objects. | 230 * This class parses JSON strings and builds the corresponding objects. |
| 200 */ | 231 */ |
| 201 class JsonDecoder extends Converter<String, Object> { | 232 class JsonDecoder extends Converter<String, Object> { |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 259 String accumulated = buffer.toString(); | 290 String accumulated = buffer.toString(); |
| 260 buffer.clear(); | 291 buffer.clear(); |
| 261 Object decoded = _parseJson(accumulated, _reviver); | 292 Object decoded = _parseJson(accumulated, _reviver); |
| 262 _chunkedSink.add(decoded); | 293 _chunkedSink.add(decoded); |
| 263 _chunkedSink.close(); | 294 _chunkedSink.close(); |
| 264 } | 295 } |
| 265 } | 296 } |
| 266 | 297 |
| 267 // Internal optimized JSON parsing implementation. | 298 // Internal optimized JSON parsing implementation. |
| 268 external _parseJson(String source, reviver(key, value)); | 299 external _parseJson(String source, reviver(key, value)); |
| OLD | NEW |