| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 /** | 5 /** |
| 6 * This provides a general-purpose serialization facility for Dart objects. A | 6 * This provides a general-purpose serialization facility for Dart objects. A |
| 7 * [Serialization] is defined in terms of [SerializationRule]s and supports | 7 * [Serialization] is defined in terms of [SerializationRule]s and supports |
| 8 * reading and writing to different formats. | 8 * reading and writing to different formats. |
| 9 * | 9 * |
| 10 * Setup | 10 * Setup |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 159 * This class defines a particular serialization scheme, in terms of | 159 * This class defines a particular serialization scheme, in terms of |
| 160 * [SerializationRule] instances, and supports reading and writing them. | 160 * [SerializationRule] instances, and supports reading and writing them. |
| 161 * See library comment for examples of usage. | 161 * See library comment for examples of usage. |
| 162 */ | 162 */ |
| 163 class Serialization { | 163 class Serialization { |
| 164 | 164 |
| 165 /** | 165 /** |
| 166 * The serialization is controlled by the list of Serialization rules. These | 166 * The serialization is controlled by the list of Serialization rules. These |
| 167 * are most commonly added via [addRuleFor]. | 167 * are most commonly added via [addRuleFor]. |
| 168 */ | 168 */ |
| 169 List rules = []; | 169 List _rules = []; |
| 170 |
| 171 /** |
| 172 * The serialization is controlled by the list of Serialization rules. These |
| 173 * are most commonly added via [addRuleFor]. |
| 174 */ |
| 175 List get rules => _rules; |
| 170 | 176 |
| 171 /** | 177 /** |
| 172 * When reading, we may need to resolve references to existing objects in | 178 * When reading, we may need to resolve references to existing objects in |
| 173 * the system. The right action may not be to create a new instance of | 179 * the system. The right action may not be to create a new instance of |
| 174 * something, but rather to find an existing instance and connect to it. | 180 * something, but rather to find an existing instance and connect to it. |
| 175 * For example, if we have are serializing an Email message and it has a | 181 * For example, if we have are serializing an Email message and it has a |
| 176 * link to the owning account, it may not be appropriate to try and serialize | 182 * link to the owning account, it may not be appropriate to try and serialize |
| 177 * the account. Instead we should just connect the de-serialized message | 183 * the account. Instead we should just connect the de-serialized message |
| 178 * object to the account object that already exists there. | 184 * object to the account object that already exists there. |
| 179 */ | 185 */ |
| 180 Map<String, dynamic> externalObjects = {}; | 186 Map<String, dynamic> namedObjects = {}; |
| 181 | 187 |
| 182 /** | 188 /** |
| 183 * When we write out data using this serialization, should we also write | 189 * When we write out data using this serialization, should we also write |
| 184 * out a description of the rules. | 190 * out a description of the rules. This is on by default unless using |
| 191 * CustomRule subclasses, in which case it requires additional setup and |
| 192 * is off by default. |
| 185 */ | 193 */ |
| 186 bool selfDescribing = true; | 194 bool _selfDescribing; |
| 195 |
| 196 /** |
| 197 * When we write out data using this serialization, should we also write |
| 198 * out a description of the rules. This is on by default unless using |
| 199 * CustomRule subclasses, in which case it requires additional setup and |
| 200 * is off by default. |
| 201 */ |
| 202 bool get selfDescribing { |
| 203 if (_selfDescribing != null) return _selfDescribing; |
| 204 return !_rules.some((x) => x is CustomRule); |
| 205 } |
| 206 |
| 207 /** |
| 208 * When we write out data using this serialization, should we also write |
| 209 * out a description of the rules. This is on by default unless using |
| 210 * CustomRule subclasses, in which case it requires additional setup and |
| 211 * is off by default. |
| 212 */ |
| 213 set selfDescribing(x) => _selfDescribing = x; |
| 187 | 214 |
| 188 /** | 215 /** |
| 189 * Creates a new serialization with a default set of rules for primitives | 216 * Creates a new serialization with a default set of rules for primitives |
| 190 * and lists. | 217 * and lists. |
| 191 */ | 218 */ |
| 192 Serialization() { | 219 Serialization() { |
| 193 addDefaultRules(); | 220 addDefaultRules(); |
| 194 } | 221 } |
| 195 | 222 |
| 196 /** | 223 /** |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 249 addRule(new ListRuleEssential()); | 276 addRule(new ListRuleEssential()); |
| 250 } | 277 } |
| 251 | 278 |
| 252 /** | 279 /** |
| 253 * Add a new SerializationRule [rule]. The addRuleFor method will probably | 280 * Add a new SerializationRule [rule]. The addRuleFor method will probably |
| 254 * handle most simple cases, but for adding an arbitrary rule, including | 281 * handle most simple cases, but for adding an arbitrary rule, including |
| 255 * a SerializationRule subclass which you have created, you can use this | 282 * a SerializationRule subclass which you have created, you can use this |
| 256 * method. | 283 * method. |
| 257 */ | 284 */ |
| 258 void addRule(SerializationRule rule) { | 285 void addRule(SerializationRule rule) { |
| 259 rule.number = rules.length; | 286 rule.number = _rules.length; |
| 260 rules.add(rule); | 287 _rules.add(rule); |
| 261 } | 288 } |
| 262 | 289 |
| 263 /** | 290 /** |
| 264 * This is the basic method to write out an object graph rooted at | 291 * This is the basic method to write out an object graph rooted at |
| 265 * [object] and return the result. Right now this is hard-coded to return | 292 * [object] and return the result. Right now this is hard-coded to return |
| 266 * a String from a custom [JSON] format, but that is likely to change to be | 293 * a String from a custom [JSON] format, but that is likely to change to be |
| 267 * more pluggable in the near future. | 294 * more pluggable in the near future. |
| 268 */ | 295 */ |
| 269 String write(Object object) { | 296 String write(Object object) { |
| 270 return newWriter().write(object); | 297 return newWriter().write(object); |
| 271 } | 298 } |
| 272 | 299 |
| 273 /** | 300 /** |
| 274 * Return a new [Writer] object for this serialization. This is useful if you | 301 * Return a new [Writer] object for this serialization. This is useful if you |
| 275 * want to do something more complex with the writer than just returning | 302 * want to do something more complex with the writer than just returning |
| 276 * the final result. | 303 * the final result. |
| 277 */ | 304 */ |
| 278 Writer newWriter() => new Writer(this); | 305 Writer newWriter() => new Writer(this); |
| 279 | 306 |
| 280 /** | 307 /** |
| 281 * Write out the tree in a custom flat format, returning a list containing | 308 * Write out the tree in a custom flat format, returning a list containing |
| 282 * only "simple" types: num, String, and bool. | 309 * only "simple" types: num, String, and bool. |
| 283 */ | 310 */ |
| 284 List writeFlat(Object object) { | 311 List writeFlat(Object object) { |
| 285 return newWriter().writeFlat(object); | 312 return newWriter().writeFlat(object); |
| 286 } | 313 } |
| 287 | 314 |
| 288 /** | 315 /** |
| 289 * Read the serialized data from [input] and return a List of the root | 316 * Read the serialized data from [input] and return the root object |
| 290 * objects from the result. If there are objects that need to be resolved | 317 * from the result. If there are objects that need to be resolved |
| 291 * in the current context, they should be provided in [externals] as a | 318 * in the current context, they should be provided in [externals] as a |
| 292 * Map from names to values. In particular, in the current implementation | 319 * Map from names to values. In particular, in the current implementation |
| 293 * any class mirrors needed should be provided in [externals] using the | 320 * any class mirrors needed should be provided in [externals] using the |
| 294 * class name as a key. In addition to the [externals] map provided here, | 321 * class name as a key. In addition to the [externals] map provided here, |
| 295 * values will be looked up in the [externalObjects] map. | 322 * values will be looked up in the [externalObjects] map. |
| 296 */ | 323 */ |
| 297 List read(String input, [Map externals = const {}]) { | 324 read(String input, [Map externals = const {}]) { |
| 298 return newReader().read(input, externals); | 325 return newReader().read(input, externals); |
| 299 } | 326 } |
| 300 | 327 |
| 301 /** | 328 /** |
| 302 * In the most common case there is only a single root object to be read, | |
| 303 * and this method can be used to return just one object rather than | |
| 304 * a List. The [input] and [externals] parameters are the same as for the | |
| 305 * general [read] method. | |
| 306 */ | |
| 307 Object readOne(String input, [Map externals = const {}]) { | |
| 308 return newReader().readOne(input, externals); | |
| 309 } | |
| 310 | |
| 311 /** | |
| 312 * Return a new [Reader] object for this serialization. This is useful if | 329 * Return a new [Reader] object for this serialization. This is useful if |
| 313 * you want to do something more complex with the reader than just returning | 330 * you want to do something more complex with the reader than just returning |
| 314 * the final result. | 331 * the final result. |
| 315 */ | 332 */ |
| 316 Reader newReader() => new Reader(this); | 333 Reader newReader() => new Reader(this); |
| 317 | 334 |
| 318 /** | 335 /** |
| 319 * Return the list of SerializationRule that apply to [object]. For | 336 * Return the list of SerializationRule that apply to [object]. For |
| 320 * internal use, but public because it's used in testing. | 337 * internal use, but public because it's used in testing. |
| 321 */ | 338 */ |
| 322 List<SerializationRule> rulesFor(object) { | 339 List<SerializationRule> rulesFor(object, Writer w) { |
| 323 // This has a couple of edge cases. | 340 // This has a couple of edge cases. |
| 324 // 1) The owning object may have indicated we should use a different | 341 // 1) The owning object may have indicated we should use a different |
| 325 // rule than the default. | 342 // rule than the default. |
| 326 // 2) We may not have a rule, in which case we lazily create a BasicRule. | 343 // 2) We may not have a rule, in which case we lazily create a BasicRule. |
| 327 // 3) Rules are allowed to say mustBePrimary, meaning that they can be used | 344 // 3) Rules are allowed to say mustBePrimary, meaning that they can be used |
| 328 // iff no other rule was chosen first. | 345 // iff no other rule was chosen first. |
| 329 // TODO(alanknight): Can the mustBePrimary mechanism be removed or changed. | 346 // TODO(alanknight): Can the mustBePrimary mechanism be removed or changed. |
| 330 // It adds an order dependency to the rules, and is messy. Reconsider in the | 347 // It adds an order dependency to the rules, and is messy. Reconsider in the |
| 331 // light of a more general mechanism for multiple rules per object. | 348 // light of a more general mechanism for multiple rules per object. |
| 332 // TODO(alanknight): Finding which rules apply seems likely to be a | 349 // TODO(alanknight): Finding which rules apply seems likely to be a |
| 333 // bottleneck, particularly with the current reflective implementation. | 350 // bottleneck, particularly with the current reflective implementation. |
| 334 // Consider how to improve it. e.g. cache the list of rules by class. But | 351 // Consider how to improve it. e.g. cache the list of rules by class. But |
| 335 // be careful of issues like rules which have arbitrary predicates. Or | 352 // be careful of issues like rules which have arbitrary predicates. Or |
| 336 // consider having the arbitrary predicates be secondary to an initial | 353 // consider having the arbitrary predicates be secondary to an initial |
| 337 // class-based lookup mechanism. | 354 // class-based lookup mechanism. |
| 338 var target, candidateRules; | 355 var target, candidateRules; |
| 339 if (object is DesignatedRuleForObject) { | 356 if (object is DesignatedRuleForObject) { |
| 340 target = object.target; | 357 target = object.target; |
| 341 candidateRules = object.possibleRules(rules); | 358 candidateRules = object.possibleRules(_rules); |
| 342 } else { | 359 } else { |
| 343 target = object; | 360 target = object; |
| 344 candidateRules = rules; | 361 candidateRules = _rules; |
| 345 } | 362 } |
| 346 List applicable = candidateRules.filter((each) => each.appliesTo(target)); | 363 List applicable = candidateRules.filter( |
| 364 (each) => each.appliesTo(target, w)); |
| 347 | 365 |
| 348 if (applicable.isEmpty) { | 366 if (applicable.isEmpty) { |
| 349 return [addRuleFor(target)]; | 367 return [addRuleFor(target)]; |
| 350 } | 368 } |
| 351 | 369 |
| 352 if (applicable.length == 1) return applicable; | 370 if (applicable.length == 1) return applicable; |
| 353 var first = applicable[0]; | 371 var first = applicable[0]; |
| 354 var finalRules = applicable.filter( | 372 var finalRules = applicable.filter( |
| 355 (x) => !x.mustBePrimary || (x == first)); | 373 (x) => !x.mustBePrimary || (x == first)); |
| 356 | 374 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 367 */ | 385 */ |
| 368 Serialization _ruleSerialization() { | 386 Serialization _ruleSerialization() { |
| 369 // TODO(alanknight): There's an extensibility issue here with new rules. | 387 // TODO(alanknight): There's an extensibility issue here with new rules. |
| 370 // TODO(alanknight): How to handle rules with closures? They have to | 388 // TODO(alanknight): How to handle rules with closures? They have to |
| 371 // exist on the other side, but we might be able to hook them up by name, | 389 // exist on the other side, but we might be able to hook them up by name, |
| 372 // or we might just be able to validate that they're correctly set up | 390 // or we might just be able to validate that they're correctly set up |
| 373 // on the other side. | 391 // on the other side. |
| 374 | 392 |
| 375 // Make some bogus rule instances so we have something to feed rule creation | 393 // Make some bogus rule instances so we have something to feed rule creation |
| 376 // and get their types. If only we had class literals implemented... | 394 // and get their types. If only we had class literals implemented... |
| 377 var closureRule = new ClosureToMapRule.stub([].runtimeType); | 395 var basicRule = new BasicRule(reflect(null).type, '', [], [], []); |
| 378 var basicRule = new BasicRule(reflect(null).type, '', [], [], []); | |
| 379 | 396 |
| 380 var meta = new Serialization() | 397 var meta = new Serialization() |
| 381 ..selfDescribing = false | 398 ..selfDescribing = false |
| 382 ..addRuleFor(new ListRule()) | 399 ..addRuleFor(new ListRule()) |
| 383 ..addRuleFor(new PrimitiveRule()) | 400 ..addRuleFor(new PrimitiveRule()) |
| 384 ..addRuleFor(new ListRuleEssential()) | 401 ..addRuleFor(new ListRuleEssential()) |
| 385 ..addRuleFor(basicRule, | 402 ..addRuleFor(basicRule, |
| 386 constructorFields: ['typeWrapped', | 403 constructorFields: ['typeWrapped', |
| 387 'constructorName', | 404 'constructorName', |
| 388 'constructorFields', 'regularFields', []], | 405 'constructorFields', 'regularFields', []], |
| 389 fields: []) | 406 fields: []) |
| 390 ..addRule(new ClassMirrorRule()); | 407 ..addRule(new NamedObjectRule()) |
| 391 meta.externalObjects = externalObjects; | 408 ..addRule(new MirrorRule()); |
| 409 meta.namedObjects = namedObjects; |
| 392 return meta; | 410 return meta; |
| 393 } | 411 } |
| 412 |
| 413 /** Return true if our [namedObjects] collection has an entry for [object].*/ |
| 414 bool _hasNameFor(object) { |
| 415 var sentinel = const _Sentinel(); |
| 416 return _nameFor(object, () => sentinel) != sentinel; |
| 417 } |
| 418 |
| 419 /** |
| 420 * Return the name we have for [object] in our [namedObjects] collection or |
| 421 * the result of evaluating [ifAbsent] if there is no entry. |
| 422 */ |
| 423 _nameFor(object, [ifAbsent]) { |
| 424 for (var key in namedObjects.keys) { |
| 425 if (identical(namedObjects[key], object)) return key; |
| 426 } |
| 427 return ifAbsent == null ? null : ifAbsent(); |
| 428 } |
| 394 } | 429 } |
| 395 | 430 |
| 396 /** | 431 /** |
| 397 * An exception class for errors during serialization. | 432 * An exception class for errors during serialization. |
| 398 */ | 433 */ |
| 399 class SerializationException implements Exception { | 434 class SerializationException implements Exception { |
| 400 final String message; | 435 final String message; |
| 401 const SerializationException([this.message]); | 436 const SerializationException([this.message]); |
| 402 } | 437 } |
| OLD | NEW |