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 |