| 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 |
| 11 * ===== | 11 * ===== |
| 12 * A simple example of usage is | 12 * A simple example of usage is |
| 13 * | 13 * |
| 14 * var address = new Address(); | 14 * var address = new Address(); |
| 15 * address.street = 'N 34th'; | 15 * address.street = 'N 34th'; |
| 16 * address.city = 'Seattle'; | 16 * address.city = 'Seattle'; |
| 17 * var serialization = new Serialization() | 17 * var serialization = new Serialization() |
| 18 * ..addRuleFor(address); | 18 * ..addRuleFor(address); |
| 19 * String output = serialization.write(address); | 19 * String output = serialization.write(address); |
| 20 * | 20 * |
| 21 * This creates a new serialization and adds a rule for address objects. Right | 21 * This creates a new serialization and adds a rule for address objects. Right |
| 22 * now it has to be passed an address instance because of limitations using | 22 * now it has to be passed an address instance because of limitations using |
| 23 * Address as a literal. Then we ask the Serialization to write the address | 23 * Address as a literal. Then we ask the Serialization to write the address |
| 24 * and we get back a String which is a [JSON] representation of the state of | 24 * and we get back a Map which is a [json]able representation of the state of |
| 25 * it and related objects. | 25 * the address and related objects. |
| 26 * | 26 * |
| 27 * The version above used reflection to automatically identify the public | 27 * The version above used reflection to automatically identify the public |
| 28 * fields of the address object. We can also specify those fields explicitly. | 28 * fields of the address object. We can also specify those fields explicitly. |
| 29 * | 29 * |
| 30 * var serialization = new Serialization() | 30 * var serialization = new Serialization() |
| 31 * ..addRuleFor(address, | 31 * ..addRuleFor(address, |
| 32 * constructor: "create", | 32 * constructor: "create", |
| 33 * constructorFields: ["number", "street"], | 33 * constructorFields: ["number", "street"], |
| 34 * fields: ["city"]); | 34 * fields: ["city"]); |
| 35 * | 35 * |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 98 * [ClosureRule]. In this case we've also had them use maps rather than | 98 * [ClosureRule]. In this case we've also had them use maps rather than |
| 99 * lists for the state, but either would work as long as the rule is | 99 * lists for the state, but either would work as long as the rule is |
| 100 * consistent with the representation it uses. We pass it the runtimeType | 100 * consistent with the representation it uses. We pass it the runtimeType |
| 101 * of the object, and functions equivalent to the methods on [CustomRule] | 101 * of the object, and functions equivalent to the methods on [CustomRule] |
| 102 * | 102 * |
| 103 * Constant Values | 103 * Constant Values |
| 104 * =============== | 104 * =============== |
| 105 * There are cases where the constructor needs values that we can't easily get | 105 * There are cases where the constructor needs values that we can't easily get |
| 106 * from the serialized object. For example, we may just want to pass null, or a | 106 * from the serialized object. For example, we may just want to pass null, or a |
| 107 * constant value. To support this, we can specify as constructor fields | 107 * constant value. To support this, we can specify as constructor fields |
| 108 * values that aren't field names. If any value isn't a String, it will be | 108 * values that aren't field names. If any value isn't a String, or is a string |
| 109 * that doesn't correspond to a field name, it will be |
| 109 * treated as a constant and passed unaltered to the constructor. | 110 * treated as a constant and passed unaltered to the constructor. |
| 110 * | 111 * |
| 111 * In some cases a non-constructor field should not be set using field | 112 * In some cases a non-constructor field should not be set using field |
| 112 * access or a setter, but should be done by calling a method. For example, it | 113 * access or a setter, but should be done by calling a method. For example, it |
| 113 * may not be possible to set a List field "foo", and you need to call an | 114 * may not be possible to set a List field "foo", and you need to call an |
| 114 * addFoo() method for each entry in the list. In these cases, if you are using | 115 * addFoo() method for each entry in the list. In these cases, if you are using |
| 115 * a BasicRule for the object you can call the setFieldWith() method. | 116 * a BasicRule for the object you can call the setFieldWith() method. |
| 116 * | 117 * |
| 117 * s..addRuleFor(fooHolderInstance).setFieldWith("foo", | 118 * s..addRuleFor(fooHolderInstance).setFieldWith("foo", |
| 118 * (parent, value) => for (var each in value) parent.addFoo(value)); | 119 * (parent, value) => for (var each in value) parent.addFoo(value)); |
| 119 * | 120 * |
| 120 * Writing | 121 * Writing |
| 121 * ======= | 122 * ======= |
| 122 * To write objects, we use the write() method. | 123 * To write objects, we use the write() method. |
| 123 * | 124 * |
| 124 * var output = serialization.write(someObject); | 125 * var output = serialization.write(someObject); |
| 125 * | 126 * |
| 126 * By default this uses a representation in which objects are represented as | 127 * By default this uses a representation in which objects are represented as |
| 127 * maps keyed by field name, but in which references between objects have been | 128 * maps keyed by field name, but in which references between objects have been |
| 128 * converted into Reference objects. This is then encoded as a [json] string. | 129 * converted into Reference objects. This is then typically encoded as |
| 130 * a [json] string, but can also be used in other ways, e.g. sent to another |
| 131 * isolate. |
| 129 * | 132 * |
| 130 * We can write objects in different formats by passing a [Format] object to | 133 * We can write objects in different formats by passing a [Format] object to |
| 131 * the [write] method or by getting a [Writer] object. The available formats | 134 * the [write] method or by getting a [Writer] object. The available formats |
| 132 * include the default, a simple "flat" format that doesn't include field names, | 135 * include the default, a simple "flat" format that doesn't include field names, |
| 133 * and a simple JSON format that produces output more suitable for talking to | 136 * and a simple JSON format that produces output more suitable for talking to |
| 134 * services that expect JSON in a predefined format. Examples of these are | 137 * services that expect JSON in a predefined format. Examples of these are |
| 135 * | 138 * |
| 136 * String output = serialization.write(address, new SimpleMapFormat()); | 139 * Map output = serialization.write(address, new SimpleMapFormat()); |
| 137 * List output = serialization.write(address, new SimpleFlatFormat()); | 140 * List output = serialization.write(address, new SimpleFlatFormat()); |
| 138 * Map output = serialization.write(address, new SimpleJsonFormat()); | 141 * var output = serialization.write(address, new SimpleJsonFormat()); |
| 139 * Or, using a [Writer] explicitly | 142 * Or, using a [Writer] explicitly |
| 140 * var writer = serialization.newWriter(new SimpleFlatFormat()); | 143 * var writer = serialization.newWriter(new SimpleFlatFormat()); |
| 141 * var output = writer.write(address); | 144 * List output = writer.write(address); |
| 142 * | 145 * |
| 143 * These representations are not yet considered stable. | 146 * These representations are not yet considered stable. |
| 144 * | 147 * |
| 145 * Reading | 148 * Reading |
| 146 * ======= | 149 * ======= |
| 147 * To read objects, the corresponding [read] method can be used. | 150 * To read objects, the corresponding [read] method can be used. |
| 148 * | 151 * |
| 149 * Address input = serialization.read(aString); | 152 * Address input = serialization.read(input); |
| 150 * | 153 * |
| 151 * When reading, the serialization instance doing the reading must be configured | 154 * When reading, the serialization instance doing the reading must be configured |
| 152 * with compatible rules to the one doing the writing. It's possible for the | 155 * with compatible rules to the one doing the writing. It's possible for the |
| 153 * rules to be different, but they need to be able to read the same | 156 * rules to be different, but they need to be able to read the same |
| 154 * representation. For most practical purposes right now they should be the | 157 * representation. For most practical purposes right now they should be the |
| 155 * same. The simplest way to achieve this is by having the serialization | 158 * same. The simplest way to achieve this is by having the serialization |
| 156 * variable [selfDescribing] be true. In that case the rules themselves are also | 159 * variable [selfDescribing] be true. In that case the rules themselves are also |
| 157 * stored along with the serialized data, and can be read back on the receiving | 160 * stored along with the serialized data, and can be read back on the receiving |
| 158 * end. Note that this may not work for all rules or all formats. The | 161 * end. Note that this may not work for all rules or all formats. The |
| 159 * [selfDescribing] variable is true by default, but the [SimpleJsonFormat] does | 162 * [selfDescribing] variable is true by default, but the [SimpleJsonFormat] does |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 228 */ | 231 */ |
| 229 bool _selfDescribing; | 232 bool _selfDescribing; |
| 230 | 233 |
| 231 /** | 234 /** |
| 232 * When we write out data using this serialization, should we also write | 235 * When we write out data using this serialization, should we also write |
| 233 * out a description of the rules. This is on by default unless using | 236 * out a description of the rules. This is on by default unless using |
| 234 * CustomRule subclasses, in which case it requires additional setup and | 237 * CustomRule subclasses, in which case it requires additional setup and |
| 235 * is off by default. | 238 * is off by default. |
| 236 */ | 239 */ |
| 237 bool get selfDescribing { | 240 bool get selfDescribing { |
| 241 // TODO(alanknight): Should this be moved to the format? |
| 242 // TODO(alanknight): Allow self-describing in the presence of CustomRule. |
| 238 if (_selfDescribing != null) return _selfDescribing; | 243 if (_selfDescribing != null) return _selfDescribing; |
| 239 return !_rules.any((x) => x is CustomRule); | 244 return !_rules.any((x) => x is CustomRule); |
| 240 } | 245 } |
| 241 | 246 |
| 242 /** | 247 /** |
| 243 * When we write out data using this serialization, should we also write | 248 * When we write out data using this serialization, should we also write |
| 244 * out a description of the rules. This is on by default unless using | 249 * out a description of the rules. This is on by default unless using |
| 245 * CustomRule subclasses, in which case it requires additional setup and | 250 * CustomRule subclasses, in which case it requires additional setup and |
| 246 * is off by default. | 251 * is off by default. |
| 247 */ | 252 */ |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 337 /** | 342 /** |
| 338 * Return a new [Writer] object for this serialization. This is useful if you | 343 * Return a new [Writer] object for this serialization. This is useful if you |
| 339 * want to do something more complex with the writer than just returning | 344 * want to do something more complex with the writer than just returning |
| 340 * the final result. | 345 * the final result. |
| 341 */ | 346 */ |
| 342 Writer newWriter([Format format]) => | 347 Writer newWriter([Format format]) => |
| 343 new Writer(this, format); | 348 new Writer(this, format); |
| 344 | 349 |
| 345 /** | 350 /** |
| 346 * Read the serialized data from [input] and return the root object | 351 * Read the serialized data from [input] and return the root object |
| 347 * from the result. If there are objects that need to be resolved | 352 * from the result. The [input] can be of any type that the [Format] |
| 353 * reads/writes, but normally will be a [List], [Map], or a simple type. |
| 354 * If there are objects that need to be resolved |
| 348 * in the current context, they should be provided in [externals] as a | 355 * in the current context, they should be provided in [externals] as a |
| 349 * Map from names to values. In particular, in the current implementation | 356 * Map from names to values. In particular, in the current implementation |
| 350 * any class mirrors needed should be provided in [externals] using the | 357 * any class mirrors needed should be provided in [externals] using the |
| 351 * class name as a key. In addition to the [externals] map provided here, | 358 * class name as a key. In addition to the [externals] map provided here, |
| 352 * values will be looked up in the [externalObjects] map. | 359 * values will be looked up in the [namedObjects] map. |
| 353 */ | 360 */ |
| 354 read(String input, [Map externals = const {}]) { | 361 read(input, [Map externals = const {}]) { |
| 355 return newReader().read(input, externals); | 362 return newReader().read(input, externals); |
| 356 } | 363 } |
| 357 | 364 |
| 358 /** | 365 /** |
| 359 * Return a new [Reader] object for this serialization. This is useful if | 366 * Return a new [Reader] object for this serialization. This is useful if |
| 360 * you want to do something more complex with the reader than just returning | 367 * you want to do something more complex with the reader than just returning |
| 361 * the final result. | 368 * the final result. |
| 362 */ | 369 */ |
| 363 Reader newReader([Format format]) => new Reader(this, format); | 370 Reader newReader([Format format]) => new Reader(this, format); |
| 364 | 371 |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 460 } | 467 } |
| 461 | 468 |
| 462 /** | 469 /** |
| 463 * An exception class for errors during serialization. | 470 * An exception class for errors during serialization. |
| 464 */ | 471 */ |
| 465 class SerializationException implements Exception { | 472 class SerializationException implements Exception { |
| 466 final String message; | 473 final String message; |
| 467 const SerializationException([this.message]); | 474 const SerializationException([this.message]); |
| 468 toString() => "SerializationException($message)"; | 475 toString() => "SerializationException($message)"; |
| 469 } | 476 } |
| OLD | NEW |