| 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 part of serialization; | 5 part of serialization; |
| 6 | 6 |
| 7 // TODO(alanknight): Figure out how to reasonably separate out the things | 7 // TODO(alanknight): Figure out how to reasonably separate out the things |
| 8 // that require reflection without making the API more awkward. Or if that is | 8 // that require reflection without making the API more awkward. Or if that is |
| 9 // in fact necessary. Maybe the tree-shaking will just remove it if unused. | 9 // in fact necessary. Maybe the tree-shaking will just remove it if unused. |
| 10 | 10 |
| 11 /** | 11 /** |
| 12 * This is the basic rule for handling "normal" objects, which have a list of | 12 * This is the basic rule for handling "normal" objects, which have a list of |
| 13 * fields and a constructor, as opposed to simple types or collections. It uses | 13 * fields and a constructor, as opposed to simple types or collections. It uses |
| 14 * mirrors to access the state, and can also use them to figure out the list | 14 * mirrors to access the state, and can also use them to figure out the list |
| 15 * of fields and the constructor if it's not provided. | 15 * of fields and the constructor if it's not provided. |
| 16 * | 16 * |
| 17 * If you call [Serialization.addRule], this is what you get. | 17 * If you call [Serialization.addRule], this is what you get. |
| 18 * | 18 * |
| 19 */ | 19 */ |
| 20 class BasicRule extends SerializationRule { | 20 class BasicRule extends SerializationRule { |
| 21 /** | 21 /** |
| 22 * The [type] is used both to find fields and to verify if the object is one | 22 * The [type] is used both to find fields and to verify if the object is one |
| 23 * that we handle. | 23 * that we handle. |
| 24 */ | 24 */ |
| 25 final ClassMirror type; | 25 final ClassMirror type; |
| 26 | 26 |
| 27 /** Used to create new objects when reading. */ | 27 /** Used to create new objects when reading. */ |
| 28 Constructor constructor; | 28 final Constructor constructor; |
| 29 | 29 |
| 30 /** This holds onto our list of fields, and can also calculate them. */ | 30 /** This holds onto our list of fields, and can also calculate them. */ |
| 31 _FieldList _fields; | 31 final _FieldList _fields; |
| 32 | 32 |
| 33 /** | 33 /** |
| 34 * Instances can either use maps or lists to hold the object's state. The list | 34 * Instances can either use maps or lists to hold the object's state. The list |
| 35 * representation is much more compact and used by default. The map | 35 * representation is much more compact and used by default. The map |
| 36 * representation is more human-readable. The default is to use lists. | 36 * representation is more human-readable. The default is to use lists. |
| 37 */ | 37 */ |
| 38 bool useMaps = false; | 38 bool useMaps = false; |
| 39 | 39 |
| 40 // TODO(alanknight) Change the type parameter once we have class literals. | 40 // TODO(alanknight) Change the type parameter once we have class literals. |
| 41 // Issue 6282. | 41 // Issue 6282. |
| 42 // TODO(alanknight) Does the comment for this format properly? | 42 // TODO(alanknight) Does the comment for this format properly? |
| 43 /** | 43 /** |
| 44 * Create this rule. Right now the user is obliged to pass a ClassMirror, | 44 * Create this rule. Right now the user is obliged to pass a ClassMirror, |
| 45 * but once we allow class literals (Issue 6282) it will support that. The | 45 * but once we allow class literals (Issue 6282) it will support that. The |
| 46 * other parameters can all be left as null, and are optional on the | 46 * other parameters can all be left as null, and are optional on the |
| 47 * [Serialization.addRule] method which is the normal caller for this. | 47 * [Serialization.addRule] method which is the normal caller for this. |
| 48 * [constructorName] is the constructor, if not the default. | 48 * [constructorName] is the constructor, if not the default. |
| 49 * [constructorFields] are the fields required to call the constructor, which | 49 * [constructorFields] are the fields required to call the constructor, which |
| 50 * is the essential state. They don't have to be actual fields, | 50 * is the essential state. They don't have to be actual fields, |
| 51 * getter/setter pairs or getter/constructor pairs are fine. Note that | 51 * getter/setter pairs or getter/constructor pairs are fine. Note that |
| 52 * the constructorFields do not need to be strings, they can be arbitrary | 52 * the constructorFields do not need to be strings, they can be arbitrary |
| 53 * values. For non-strings, these will be treated as constant values to be | 53 * values. For non-strings, these will be treated as constant values to be |
| 54 * used instead of data read from the objects. | 54 * used instead of data read from the objects. |
| 55 * [regularFields] are the non-essential fields. They don't have to be actual | 55 * [regularFields] are the non-essential fields. They don't have to be actual |
| 56 * fields, getter/setter pairs are fine. If this is null, it's assumed | 56 * fields, getter/setter pairs are fine. If this is null, it's assumed |
| 57 * that we should figure them out. | 57 * that we should figure them out. |
| 58 * [excludeFields] lets you tell it to find the fields automatically, but | 58 * [excludeFields] lets you tell it to find the fields automatically, but |
| 59 * omit some that would otherwise be included. | 59 * omit some that would otherwise be included. |
| 60 */ | 60 */ |
| 61 BasicRule(ClassMirror this.type, String constructorName, | 61 factory BasicRule(ClassMirror type, String constructorName, |
| 62 List constructorFields, List regularFields, | 62 List constructorFields, List regularFields, List excludeFields) { |
| 63 List excludeFields) { | 63 |
| 64 _findFields(constructorFields, regularFields, excludeFields); | 64 var fields = new _FieldList(type); |
| 65 constructor = new Constructor( | 65 fields.constructorFields = constructorFields; |
| 66 type, constructorName, _fields.constructorFieldIndices()); | 66 fields.regular = regularFields; |
| 67 // TODO(alanknight): The order of this matters. It shouldn't. |
| 68 fields.exclude = excludeFields; |
| 69 fields.figureOutFields(); |
| 70 |
| 71 var constructor = new Constructor(type, constructorName, |
| 72 fields.constructorFieldIndices()); |
| 73 |
| 74 return new BasicRule._(type, constructor, fields); |
| 75 } |
| 76 |
| 77 BasicRule._(this.type, this.constructor, this._fields) { |
| 67 configureForLists(); | 78 configureForLists(); |
| 68 } | 79 } |
| 69 | 80 |
| 70 /** | 81 /** |
| 71 * Sometimes it's necessary to treat fields of an object differently, based | 82 * Sometimes it's necessary to treat fields of an object differently, based |
| 72 * on the containing object. For example, by default a list treats its | 83 * on the containing object. For example, by default a list treats its |
| 73 * contents as non-essential state, so it will be populated only after all | 84 * contents as non-essential state, so it will be populated only after all |
| 74 * objects have been created. An object may have a list which is used in its | 85 * objects have been created. An object may have a list which is used in its |
| 75 * constructor and must be fully created before the owning object can be | 86 * constructor and must be fully created before the owning object can be |
| 76 * created. Alternatively, it may not be possible to set a field directly, | 87 * created. Alternatively, it may not be possible to set a field directly, |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 236 }); | 247 }); |
| 237 } | 248 } |
| 238 | 249 |
| 239 /** | 250 /** |
| 240 * Determine if this rule applies to the object in question. In our case | 251 * Determine if this rule applies to the object in question. In our case |
| 241 * this is true if the type mirrors are the same. | 252 * this is true if the type mirrors are the same. |
| 242 */ | 253 */ |
| 243 // TODO(alanknight): This seems likely to be slow. Verify. Other options? | 254 // TODO(alanknight): This seems likely to be slow. Verify. Other options? |
| 244 bool appliesTo(object, Writer w) => reflect(object).type == type; | 255 bool appliesTo(object, Writer w) => reflect(object).type == type; |
| 245 | 256 |
| 246 /** | |
| 247 * Given the various field lists provided by the user, construct the list | |
| 248 * of field names that we want. | |
| 249 */ | |
| 250 void _findFields(List constructorFields, List regularFields, | |
| 251 List excludeFields) { | |
| 252 _fields = new _FieldList(type); | |
| 253 _fields.constructorFields = constructorFields; | |
| 254 _fields.regular = regularFields; | |
| 255 // TODO(alanknight): The order of this matters. It shouldn't. | |
| 256 _fields.exclude = excludeFields; | |
| 257 _fields.figureOutFields(); | |
| 258 } | |
| 259 | |
| 260 bool get hasVariableLengthEntries => false; | 257 bool get hasVariableLengthEntries => false; |
| 261 | 258 |
| 262 int get dataLength => _fields.length; | 259 int get dataLength => _fields.length; |
| 263 | 260 |
| 264 /** | 261 /** |
| 265 * Extract the value of [field] from the object reflected | 262 * Extract the value of [field] from the object reflected |
| 266 * by [mirror]. | 263 * by [mirror]. |
| 267 */ | 264 */ |
| 268 // TODO(alanknight): The framework should be resilient if there are fields | 265 // TODO(alanknight): The framework should be resilient if there are fields |
| 269 // it expects that are missing, either for the case of de-serializing to a | 266 // it expects that are missing, either for the case of de-serializing to a |
| (...skipping 403 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 673 if (value is String) { | 670 if (value is String) { |
| 674 try { | 671 try { |
| 675 return new Symbol(value); | 672 return new Symbol(value); |
| 676 } on ArgumentError { | 673 } on ArgumentError { |
| 677 return null; | 674 return null; |
| 678 }; | 675 }; |
| 679 } else { | 676 } else { |
| 680 return null; | 677 return null; |
| 681 } | 678 } |
| 682 } | 679 } |
| OLD | NEW |