| 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 * ## Installing ## | 10 * ## Installing ## |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 70 * class AddressRule extends CustomRule { | 70 * class AddressRule extends CustomRule { |
| 71 * bool appliesTo(instance, Writer w) => instance.runtimeType == Address; | 71 * bool appliesTo(instance, Writer w) => instance.runtimeType == Address; |
| 72 * getState(instance) => [instance.street, instance.city]; | 72 * getState(instance) => [instance.street, instance.city]; |
| 73 * create(state) => new Address(); | 73 * create(state) => new Address(); |
| 74 * setState(Address a, List state) { | 74 * setState(Address a, List state) { |
| 75 * a.street = state[0]; | 75 * a.street = state[0]; |
| 76 * a.city = state[1]; | 76 * a.city = state[1]; |
| 77 * } | 77 * } |
| 78 * } | 78 * } |
| 79 * | 79 * |
| 80 * The class needs four different methods. The [appliesTo] method tells us if | 80 * The class needs four different methods. The [CustomRule.appliesTo] |
| 81 * method tells us if |
| 81 * the rule should be used to write an object. In this example we use a test | 82 * the rule should be used to write an object. In this example we use a test |
| 82 * based on runtimeType. We could also use an "is Address" test, but if Address | 83 * based on runtimeType. We could also use an "is Address" test, but if Address |
| 83 * has subclasses that would find those as well, and we want a separate rule | 84 * has subclasses that would find those as well, and we want a separate rule |
| 84 * for each. The [getState] method should | 85 * for each. The [CustomRule.getState] method should |
| 85 * return all the state of the object that we want to recreate, | 86 * return all the state of the object that we want to recreate, |
| 86 * and should be either a Map or a List. If you want to write to human-readable | 87 * and should be either a Map or a List. If you want to write to human-readable |
| 87 * formats where it's useful to be able to look at the data as a map from | 88 * formats where it's useful to be able to look at the data as a map from |
| 88 * field names to values, then it's better to return it as a map. Otherwise it's | 89 * field names to values, then it's better to return it as a map. Otherwise it's |
| 89 * more efficient to return it as a list. You just need to be sure that the | 90 * more efficient to return it as a list. You just need to be sure that the |
| 90 * [create] and [setState] methods interpret the same way as [getState] does. | 91 * [CustomRule.create] and [CustomRule.setState] methods interpret the data the |
| 92 * same way as [CustomRule.getState] does. |
| 91 * | 93 * |
| 92 * The [create] method will create the new object and return it. While it's | 94 * The [CustomRule.create] method will create the new object and return it. Whil
e it's |
| 93 * possible to create the object and set all its state in this one method, that | 95 * possible to create the object and set all its state in this one method, that |
| 94 * increases the likelihood of problems with cycles. So it's better to use the | 96 * increases the likelihood of problems with cycles. So it's better to use the |
| 95 * minimum necessary information in [create] and do more of the work in | 97 * minimum necessary information in [CustomRule.create] and do more of the work |
| 96 * [setState]. | 98 * in [CustomRule.setState]. |
| 97 * | 99 * |
| 98 * The other way to do this is not creating a subclass, but by using a | 100 * The other way to do this is not creating a subclass, but by using a |
| 99 * [ClosureRule] and giving it functions for how to create | 101 * [ClosureRule] and giving it functions for how to create |
| 100 * the address. | 102 * the address. |
| 101 * | 103 * |
| 102 * addressToMap(a) => {"number" : a.number, "street" : a.street, | 104 * addressToMap(a) => {"number" : a.number, "street" : a.street, |
| 103 * "city" : a.city}; | 105 * "city" : a.city}; |
| 104 * createAddress(Map m) => new Address.create(m["number"], m["street"]); | 106 * createAddress(Map m) => new Address.create(m["number"], m["street"]); |
| 105 * fillInAddress(Address a, Map m) => a.city = m["city"]; | 107 * fillInAddress(Address a, Map m) => a.city = m["city"]; |
| 106 * var serialization = new Serialization() | 108 * var serialization = new Serialization() |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 139 * | 141 * |
| 140 * var output = serialization.write(someObject); | 142 * var output = serialization.write(someObject); |
| 141 * | 143 * |
| 142 * By default this uses a representation in which objects are represented as | 144 * By default this uses a representation in which objects are represented as |
| 143 * maps keyed by field name, but in which references between objects have been | 145 * maps keyed by field name, but in which references between objects have been |
| 144 * converted into Reference objects. This is then typically encoded as | 146 * converted into Reference objects. This is then typically encoded as |
| 145 * a [json] string, but can also be used in other ways, e.g. sent to another | 147 * a [json] string, but can also be used in other ways, e.g. sent to another |
| 146 * isolate. | 148 * isolate. |
| 147 * | 149 * |
| 148 * We can write objects in different formats by passing a [Format] object to | 150 * We can write objects in different formats by passing a [Format] object to |
| 149 * the [write] method or by getting a [Writer] object. The available formats | 151 * the [Serialization.write] method or by getting a [Writer] object. |
| 152 * The available formats |
| 150 * include the default, a simple "flat" format that doesn't include field names, | 153 * include the default, a simple "flat" format that doesn't include field names, |
| 151 * and a simple JSON format that produces output more suitable for talking to | 154 * and a simple JSON format that produces output more suitable for talking to |
| 152 * services that expect JSON in a predefined format. Examples of these are | 155 * services that expect JSON in a predefined format. Examples of these are |
| 153 * | 156 * |
| 154 * Map output = serialization.write(address, new SimpleMapFormat()); | 157 * Map output = serialization.write(address, new SimpleMapFormat()); |
| 155 * List output = serialization.write(address, new SimpleFlatFormat()); | 158 * List output = serialization.write(address, new SimpleFlatFormat()); |
| 156 * var output = serialization.write(address, new SimpleJsonFormat()); | 159 * var output = serialization.write(address, new SimpleJsonFormat()); |
| 157 * Or, using a [Writer] explicitly | 160 * Or, using a [Writer] explicitly |
| 158 * var writer = serialization.newWriter(new SimpleFlatFormat()); | 161 * var writer = serialization.newWriter(new SimpleFlatFormat()); |
| 159 * List output = writer.write(address); | 162 * List output = writer.write(address); |
| 160 * | 163 * |
| 161 * These representations are not yet considered stable. | 164 * These representations are not yet considered stable. |
| 162 * | 165 * |
| 163 * Reading | 166 * Reading |
| 164 * ======= | 167 * ======= |
| 165 * To read objects, the corresponding [read] method can be used. | 168 * To read objects, the corresponding [Serialization.read] method can be used. |
| 166 * | 169 * |
| 167 * Address input = serialization.read(input); | 170 * Address input = serialization.read(input); |
| 168 * | 171 * |
| 169 * When reading, the serialization instance doing the reading must be configured | 172 * When reading, the serialization instance doing the reading must be configured |
| 170 * with compatible rules to the one doing the writing. It's possible for the | 173 * with compatible rules to the one doing the writing. It's possible for the |
| 171 * rules to be different, but they need to be able to read the same | 174 * rules to be different, but they need to be able to read the same |
| 172 * representation. For most practical purposes right now they should be the | 175 * representation. For most practical purposes right now they should be the |
| 173 * same. The simplest way to achieve this is by having the serialization | 176 * same. The simplest way to achieve this is by having the serialization |
| 174 * variable [selfDescribing] be true. In that case the rules themselves are also | 177 * variable [Serialization.selfDescribing] be true. In that case the rules |
| 178 * themselves are also |
| 175 * stored along with the serialized data, and can be read back on the receiving | 179 * stored along with the serialized data, and can be read back on the receiving |
| 176 * end. Note that this may not work for all rules or all formats. The | 180 * end. Note that this may not work for all rules or all formats. The |
| 177 * [selfDescribing] variable is true by default, but the [SimpleJsonFormat] does | 181 * [Serialization.selfDescribing] variable is true by default, but the |
| 178 * not support it, since the point is to provide a representation in a form | 182 * [SimpleJsonFormat] does not support it, since the point is to provide a |
| 183 * representation in a form |
| 179 * other services might expect. Using CustomRule or ClosureRule also does not | 184 * other services might expect. Using CustomRule or ClosureRule also does not |
| 180 * yet work with the [selfDescribing] variable. | 185 * yet work with the [Serialization.selfDescribing] variable. |
| 181 * | 186 * |
| 182 * Named Objects | 187 * Named Objects |
| 183 * ============= | 188 * ============= |
| 184 * When reading, some object references should not be serialized, but should be | 189 * When reading, some object references should not be serialized, but should be |
| 185 * connected up to other instances on the receiving side. A notable example of | 190 * connected up to other instances on the receiving side. A notable example of |
| 186 * this is when serialization rules have been stored. Instances of BasicRule | 191 * this is when serialization rules have been stored. Instances of BasicRule |
| 187 * take a [ClassMirror] in their constructor, and we cannot serialize those. So | 192 * take a [ClassMirror] in their constructor, and we cannot serialize those. So |
| 188 * when we read the rules, we must provide a Map<String, Object> which maps from | 193 * when we read the rules, we must provide a Map<String, Object> which maps from |
| 189 * the simple name of classes we are interested in to a [ClassMirror]. This can | 194 * the simple name of classes we are interested in to a [ClassMirror]. This can |
| 190 * be provided either in the [namedObjects] variable of the Serialization, | 195 * be provided either in the [Serialization.namedObjects], |
| 191 * or as an additional parameter to the reading and writing methods on the | 196 * or as an additional parameter to the reading and writing methods on the |
| 192 * [Reader] or [Writer] respectively. | 197 * [Reader] or [Writer] respectively. |
| 193 * | 198 * |
| 194 * new Serialization() | 199 * new Serialization() |
| 195 * ..addRuleFor(new Person(), constructorFields: ["name"]) | 200 * ..addRuleFor(new Person(), constructorFields: ["name"]) |
| 196 * ..namedObjects['Person'] = reflect(new Person()).type; | 201 * ..namedObjects['Person'] = reflect(new Person()).type; |
| 197 * | 202 * |
| 198 * [pub]: http://pub.dartlang.org | 203 * [pub]: http://pub.dartlang.org |
| 199 * [pkg]: http://pub.dartlang.org/packages/serialization | 204 * [pkg]: http://pub.dartlang.org/packages/serialization |
| 200 */ | 205 */ |
| (...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 487 } | 492 } |
| 488 | 493 |
| 489 /** | 494 /** |
| 490 * An exception class for errors during serialization. | 495 * An exception class for errors during serialization. |
| 491 */ | 496 */ |
| 492 class SerializationException implements Exception { | 497 class SerializationException implements Exception { |
| 493 final String message; | 498 final String message; |
| 494 const SerializationException([this.message]); | 499 const SerializationException([this.message]); |
| 495 toString() => "SerializationException($message)"; | 500 toString() => "SerializationException($message)"; |
| 496 } | 501 } |
| OLD | NEW |