| 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 * A general-purpose serialization facility for Dart objects. |
| 7 * [Serialization] is defined in terms of [SerializationRule]s and supports | 7 * |
| 8 * A [Serialization] is defined in terms of [SerializationRule]s and supports |
| 8 * reading and writing to different formats. | 9 * reading and writing to different formats. |
| 9 * | 10 * |
| 10 * ## Installing ## | 11 * For information on installing and importing this library, see the |
| 12 * [serialization package on pub.dartlang.org] |
| 13 * (http://pub.dartlang.org/packages/serialization). |
| 11 * | 14 * |
| 12 * Use [pub][] to install this package. Add the following to your `pubspec.yaml` | 15 * ## Setup |
| 13 * file. | |
| 14 * | 16 * |
| 15 * dependencies: | |
| 16 * serialization: any | |
| 17 * | |
| 18 * Then run `pub install`. | |
| 19 * | |
| 20 * For more information, see the | |
| 21 * [serialization package on pub.dartlang.org][pkg]. | |
| 22 * | |
| 23 * Setup | |
| 24 * ===== | |
| 25 * A simple example of usage is | 17 * A simple example of usage is |
| 26 * | 18 * |
| 27 * var address = new Address(); | 19 * var address = new Address(); |
| 28 * address.street = 'N 34th'; | 20 * address.street = 'N 34th'; |
| 29 * address.city = 'Seattle'; | 21 * address.city = 'Seattle'; |
| 30 * var serialization = new Serialization() | 22 * var serialization = new Serialization() |
| 31 * ..addRuleFor(address); | 23 * ..addRuleFor(address); |
| 32 * Map output = serialization.write(address); | 24 * Map output = serialization.write(address); |
| 33 * | 25 * |
| 34 * This creates a new serialization and adds a rule for address objects. Right | 26 * This creates a new serialization and adds a rule for address objects. Right |
| (...skipping 17 matching lines...) Expand all Loading... |
| 52 * identify which fields to use, but instead uses only the "number" and "street" | 44 * identify which fields to use, but instead uses only the "number" and "street" |
| 53 * fields that we specified. We may also want to tell it to identify the | 45 * fields that we specified. We may also want to tell it to identify the |
| 54 * fields, but to specifically omit certain fields that we don't want | 46 * fields, but to specifically omit certain fields that we don't want |
| 55 * serialized. | 47 * serialized. |
| 56 * | 48 * |
| 57 * var serialization = new Serialization() | 49 * var serialization = new Serialization() |
| 58 * ..addRuleFor(address, | 50 * ..addRuleFor(address, |
| 59 * constructor: "", | 51 * constructor: "", |
| 60 * excludeFields: ["other", "stuff"]); | 52 * excludeFields: ["other", "stuff"]); |
| 61 * | 53 * |
| 62 * Writing Rules | 54 * ## Writing rules |
| 63 * ============= | 55 * |
| 64 * We can also use a completely non-reflective rule to serialize and | 56 * We can also use a completely non-reflective rule to serialize and |
| 65 * de-serialize objects. This can be more work, but it does work in | 57 * de-serialize objects. This can be more work, but it does work in |
| 66 * dart2js, where mirrors are not yet implemented. We can specify this in two | 58 * dart2js, where mirrors are not yet implemented. We can specify this in two |
| 67 * ways. First, we can write our own SerializationRule class that has methods | 59 * ways. First, we can write our own SerializationRule class that has methods |
| 68 * for our Address class. | 60 * for our Address class. |
| 69 * | 61 * |
| 70 * class AddressRule extends CustomRule { | 62 * class AddressRule extends CustomRule { |
| 71 * bool appliesTo(instance, Writer w) => instance.runtimeType == Address; | 63 * bool appliesTo(instance, Writer w) => instance.runtimeType == Address; |
| 72 * getState(instance) => [instance.street, instance.city]; | 64 * getState(instance) => [instance.street, instance.city]; |
| 73 * create(state) => new Address(); | 65 * create(state) => new Address(); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 110 * new ClosureRule(anAddress.runtimeType, | 102 * new ClosureRule(anAddress.runtimeType, |
| 111 * addressToMap, createAddress, fillInAddress); | 103 * addressToMap, createAddress, fillInAddress); |
| 112 * | 104 * |
| 113 * In this case we have created standalone functions rather than | 105 * In this case we have created standalone functions rather than |
| 114 * methods in a subclass and we pass them to the constructor of | 106 * methods in a subclass and we pass them to the constructor of |
| 115 * [ClosureRule]. In this case we've also had them use maps rather than | 107 * [ClosureRule]. In this case we've also had them use maps rather than |
| 116 * lists for the state, but either would work as long as the rule is | 108 * lists for the state, but either would work as long as the rule is |
| 117 * consistent with the representation it uses. We pass it the runtimeType | 109 * consistent with the representation it uses. We pass it the runtimeType |
| 118 * of the object, and functions equivalent to the methods on [CustomRule] | 110 * of the object, and functions equivalent to the methods on [CustomRule] |
| 119 * | 111 * |
| 120 * Constant Values | 112 * ## Constant values |
| 121 * =============== | 113 * |
| 122 * There are cases where the constructor needs values that we can't easily get | 114 * There are cases where the constructor needs values that we can't easily get |
| 123 * from the serialized object. For example, we may just want to pass null, or a | 115 * from the serialized object. For example, we may just want to pass null, or a |
| 124 * constant value. To support this, we can specify as constructor fields | 116 * constant value. To support this, we can specify as constructor fields |
| 125 * values that aren't field names. If any value isn't a String, or is a string | 117 * values that aren't field names. If any value isn't a String, or is a string |
| 126 * that doesn't correspond to a field name, it will be | 118 * that doesn't correspond to a field name, it will be |
| 127 * treated as a constant and passed unaltered to the constructor. | 119 * treated as a constant and passed unaltered to the constructor. |
| 128 * | 120 * |
| 129 * In some cases a non-constructor field should not be set using field | 121 * In some cases a non-constructor field should not be set using field |
| 130 * access or a setter, but should be done by calling a method. For example, it | 122 * access or a setter, but should be done by calling a method. For example, it |
| 131 * may not be possible to set a List field "foo", and you need to call an | 123 * may not be possible to set a List field "foo", and you need to call an |
| 132 * addFoo() method for each entry in the list. In these cases, if you are using | 124 * addFoo() method for each entry in the list. In these cases, if you are using |
| 133 * a BasicRule for the object you can call the setFieldWith() method. | 125 * a BasicRule for the object you can call the setFieldWith() method. |
| 134 * | 126 * |
| 135 * s..addRuleFor(fooHolderInstance).setFieldWith("foo", | 127 * s..addRuleFor(fooHolderInstance).setFieldWith("foo", |
| 136 * (parent, value) => for (var each in value) parent.addFoo(value)); | 128 * (parent, value) => for (var each in value) parent.addFoo(value)); |
| 137 * | 129 * |
| 138 * Writing | 130 * ## Writing |
| 139 * ======= | 131 * |
| 140 * To write objects, we use the write() method. | 132 * To write objects, we use the write() method. |
| 141 * | 133 * |
| 142 * var output = serialization.write(someObject); | 134 * var output = serialization.write(someObject); |
| 143 * | 135 * |
| 144 * By default this uses a representation in which objects are represented as | 136 * By default this uses a representation in which objects are represented as |
| 145 * maps keyed by field name, but in which references between objects have been | 137 * maps keyed by field name, but in which references between objects have been |
| 146 * converted into Reference objects. This is then typically encoded as | 138 * converted into Reference objects. This is then typically encoded as |
| 147 * a [json] string, but can also be used in other ways, e.g. sent to another | 139 * a [json] string, but can also be used in other ways, e.g. sent to another |
| 148 * isolate. | 140 * isolate. |
| 149 * | 141 * |
| 150 * We can write objects in different formats by passing a [Format] object to | 142 * We can write objects in different formats by passing a [Format] object to |
| 151 * the [Serialization.write] method or by getting a [Writer] object. | 143 * the [Serialization.write] method or by getting a [Writer] object. |
| 152 * The available formats | 144 * The available formats |
| 153 * include the default, a simple "flat" format that doesn't include field names, | 145 * include the default, a simple "flat" format that doesn't include field names, |
| 154 * and a simple JSON format that produces output more suitable for talking to | 146 * and a simple JSON format that produces output more suitable for talking to |
| 155 * services that expect JSON in a predefined format. Examples of these are | 147 * services that expect JSON in a predefined format. Examples of these are |
| 156 * | 148 * |
| 157 * Map output = serialization.write(address, new SimpleMapFormat()); | 149 * Map output = serialization.write(address, new SimpleMapFormat()); |
| 158 * List output = serialization.write(address, new SimpleFlatFormat()); | 150 * List output = serialization.write(address, new SimpleFlatFormat()); |
| 159 * var output = serialization.write(address, new SimpleJsonFormat()); | 151 * var output = serialization.write(address, new SimpleJsonFormat()); |
| 160 * Or, using a [Writer] explicitly | 152 * Or, using a [Writer] explicitly |
| 161 * var writer = serialization.newWriter(new SimpleFlatFormat()); | 153 * var writer = serialization.newWriter(new SimpleFlatFormat()); |
| 162 * List output = writer.write(address); | 154 * List output = writer.write(address); |
| 163 * | 155 * |
| 164 * These representations are not yet considered stable. | 156 * These representations are not yet considered stable. |
| 165 * | 157 * |
| 166 * Reading | 158 * ## Reading |
| 167 * ======= | 159 * |
| 168 * To read objects, the corresponding [Serialization.read] method can be used. | 160 * To read objects, the corresponding [Serialization.read] method can be used. |
| 169 * | 161 * |
| 170 * Address input = serialization.read(input); | 162 * Address input = serialization.read(input); |
| 171 * | 163 * |
| 172 * When reading, the serialization instance doing the reading must be configured | 164 * When reading, the serialization instance doing the reading must be configured |
| 173 * with compatible rules to the one doing the writing. It's possible for the | 165 * with compatible rules to the one doing the writing. It's possible for the |
| 174 * rules to be different, but they need to be able to read the same | 166 * rules to be different, but they need to be able to read the same |
| 175 * representation. For most practical purposes right now they should be the | 167 * representation. For most practical purposes right now they should be the |
| 176 * same. The simplest way to achieve this is by having the serialization | 168 * same. The simplest way to achieve this is by having the serialization |
| 177 * variable [Serialization.selfDescribing] be true. In that case the rules | 169 * variable [Serialization.selfDescribing] be true. In that case the rules |
| 178 * themselves are also | 170 * themselves are also |
| 179 * stored along with the serialized data, and can be read back on the receiving | 171 * stored along with the serialized data, and can be read back on the receiving |
| 180 * end. Note that this may not work for all rules or all formats. The | 172 * end. Note that this may not work for all rules or all formats. The |
| 181 * [Serialization.selfDescribing] variable is true by default, but the | 173 * [Serialization.selfDescribing] variable is true by default, but the |
| 182 * [SimpleJsonFormat] does not support it, since the point is to provide a | 174 * [SimpleJsonFormat] does not support it, since the point is to provide a |
| 183 * representation in a form | 175 * representation in a form |
| 184 * other services might expect. Using CustomRule or ClosureRule also does not | 176 * other services might expect. Using CustomRule or ClosureRule also does not |
| 185 * yet work with the [Serialization.selfDescribing] variable. | 177 * yet work with the [Serialization.selfDescribing] variable. |
| 186 * | 178 * |
| 187 * Named Objects | 179 * ## Named objects |
| 188 * ============= | 180 * |
| 189 * When reading, some object references should not be serialized, but should be | 181 * When reading, some object references should not be serialized, but should be |
| 190 * connected up to other instances on the receiving side. A notable example of | 182 * connected up to other instances on the receiving side. A notable example of |
| 191 * this is when serialization rules have been stored. Instances of BasicRule | 183 * this is when serialization rules have been stored. Instances of BasicRule |
| 192 * take a [ClassMirror] in their constructor, and we cannot serialize those. So | 184 * take a [ClassMirror] in their constructor, and we cannot serialize those. So |
| 193 * when we read the rules, we must provide a Map<String, Object> which maps from | 185 * when we read the rules, we must provide a Map<String, Object> which maps from |
| 194 * the simple name of classes we are interested in to a [ClassMirror]. This can | 186 * the simple name of classes we are interested in to a [ClassMirror]. This can |
| 195 * be provided either in the [Serialization.namedObjects], | 187 * be provided either in the [Serialization.namedObjects], |
| 196 * or as an additional parameter to the reading and writing methods on the | 188 * or as an additional parameter to the reading and writing methods on the |
| 197 * [Reader] or [Writer] respectively. | 189 * [Reader] or [Writer] respectively. |
| 198 * | 190 * |
| 199 * new Serialization() | 191 * new Serialization() |
| 200 * ..addRuleFor(new Person(), constructorFields: ["name"]) | 192 * ..addRuleFor(new Person(), constructorFields: ["name"]) |
| 201 * ..namedObjects['Person'] = reflect(new Person()).type; | 193 * ..namedObjects['Person'] = reflect(new Person()).type; |
| 202 * | |
| 203 * [pub]: http://pub.dartlang.org | |
| 204 * [pkg]: http://pub.dartlang.org/packages/serialization | |
| 205 */ | 194 */ |
| 206 library serialization; | 195 library serialization; |
| 207 | 196 |
| 208 import 'src/mirrors_helpers.dart'; | 197 import 'src/mirrors_helpers.dart'; |
| 209 import 'src/serialization_helpers.dart'; | 198 import 'src/serialization_helpers.dart'; |
| 210 import 'dart:collection'; | 199 import 'dart:collection'; |
| 211 | 200 |
| 212 part 'src/reader_writer.dart'; | 201 part 'src/reader_writer.dart'; |
| 213 part 'src/serialization_rule.dart'; | 202 part 'src/serialization_rule.dart'; |
| 214 part 'src/basic_rule.dart'; | 203 part 'src/basic_rule.dart'; |
| (...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 501 } | 490 } |
| 502 | 491 |
| 503 /** | 492 /** |
| 504 * An exception class for errors during serialization. | 493 * An exception class for errors during serialization. |
| 505 */ | 494 */ |
| 506 class SerializationException implements Exception { | 495 class SerializationException implements Exception { |
| 507 final String message; | 496 final String message; |
| 508 const SerializationException(this.message); | 497 const SerializationException(this.message); |
| 509 String toString() => "SerializationException($message)"; | 498 String toString() => "SerializationException($message)"; |
| 510 } | 499 } |
| OLD | NEW |