| 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 |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 87 * For example, to serialize a Serialization, we need its rules to be | 87 * For example, to serialize a Serialization, we need its rules to be |
| 88 * individually added rather than just setting the rules field. | 88 * individually added rather than just setting the rules field. |
| 89 * ..addRuleFor(new Serialization()).setFieldWith('rules', | 89 * ..addRuleFor(new Serialization()).setFieldWith('rules', |
| 90 * (InstanceMirror s, List rules) { | 90 * (InstanceMirror s, List rules) { |
| 91 * rules.forEach((x) => s.reflectee.addRule(x)); | 91 * rules.forEach((x) => s.reflectee.addRule(x)); |
| 92 * Note that the function is passed the owning object as well as the field | 92 * Note that the function is passed the owning object as well as the field |
| 93 * value, but that it is passed as a mirror. | 93 * value, but that it is passed as a mirror. |
| 94 */ | 94 */ |
| 95 setFieldWith(String fieldName, SetWithFunction setWith) { | 95 setFieldWith(String fieldName, SetWithFunction setWith) { |
| 96 fields.addAllByName([fieldName]); | 96 fields.addAllByName([fieldName]); |
| 97 _NamedField field = fields.named(fieldName); | 97 _NamedField field = fields.named(_asSymbol(fieldName)); |
| 98 Function setter = (setWith == null) ? field.defaultSetter : setWith; | 98 Function setter = (setWith == null) ? field.defaultSetter : setWith; |
| 99 field.customSetter = setter; | 99 field.customSetter = setter; |
| 100 } | 100 } |
| 101 | 101 |
| 102 /** Return the name of the constructor used to create new instances on read.*/ | 102 /** Return the name of the constructor used to create new instances on read.*/ |
| 103 String get constructorName => constructor.name; | 103 String get constructorName => constructor.name; |
| 104 | 104 |
| 105 /** Return the list of field names to be passed to the constructor.*/ | 105 /** Return the list of field names to be passed to the constructor.*/ |
| 106 List<String> get constructorFields => fields.constructorFieldNames(); | 106 List<String> get constructorFields => fields.constructorFieldNames(); |
| 107 | 107 |
| (...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 303 } else { | 303 } else { |
| 304 return new _ConstantField._internal(value, fieldList); | 304 return new _ConstantField._internal(value, fieldList); |
| 305 } | 305 } |
| 306 } | 306 } |
| 307 | 307 |
| 308 /** | 308 /** |
| 309 * Determine if [value] represents a field or getter in the class that | 309 * Determine if [value] represents a field or getter in the class that |
| 310 * [fieldList] models. | 310 * [fieldList] models. |
| 311 */ | 311 */ |
| 312 static bool _isReallyAField(value, _FieldList fieldList) { | 312 static bool _isReallyAField(value, _FieldList fieldList) { |
| 313 if (!(value is String)) return false; | 313 var symbol = _asSymbol(value); |
| 314 return hasField(value, fieldList.mirror) || | 314 return hasField(symbol, fieldList.mirror) || |
| 315 hasGetter(value, fieldList.mirror); | 315 hasGetter(symbol, fieldList.mirror); |
| 316 } | 316 } |
| 317 | 317 |
| 318 /** Private constructor. */ | 318 /** Private constructor. */ |
| 319 _Field._internal(this.fieldList); | 319 _Field._internal(this.fieldList); |
| 320 | 320 |
| 321 /** | 321 /** |
| 322 * Extracts the value for the field that this represents from the instance | 322 * Extracts the value for the field that this represents from the instance |
| 323 * mirrored by [mirror] and return it. | 323 * mirrored by [mirror] and return it. |
| 324 */ | 324 */ |
| 325 valueIn(InstanceMirror mirror); | 325 valueIn(InstanceMirror mirror); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 345 compareTo(_Field x) => toString().compareTo(x.toString()); | 345 compareTo(_Field x) => toString().compareTo(x.toString()); |
| 346 } | 346 } |
| 347 | 347 |
| 348 /** | 348 /** |
| 349 * This represents a field in the object, either stored as a field or | 349 * This represents a field in the object, either stored as a field or |
| 350 * accessed via getter/setter/constructor parameter. It has a name and | 350 * accessed via getter/setter/constructor parameter. It has a name and |
| 351 * will attempt to access the state for that name using an [InstanceMirror]. | 351 * will attempt to access the state for that name using an [InstanceMirror]. |
| 352 */ | 352 */ |
| 353 class _NamedField extends _Field { | 353 class _NamedField extends _Field { |
| 354 /** The name of the field (or getter) */ | 354 /** The name of the field (or getter) */ |
| 355 final name; | 355 String _name; |
| 356 Symbol nameSymbol; |
| 356 | 357 |
| 357 /** The special way to set this value registered, if this has a value. */ | 358 /** |
| 359 * If this is set, then it is used as a way to set the value rather than |
| 360 * using the default mechanism. |
| 361 */ |
| 358 Function customSetter; | 362 Function customSetter; |
| 359 | 363 |
| 360 _NamedField._internal(this.name, fieldList) : super._internal(fieldList); | 364 _NamedField._internal(fieldName, fieldList) : super._internal(fieldList) { |
| 365 nameSymbol = _asSymbol(fieldName); |
| 366 if (nameSymbol == null) { |
| 367 throw new SerializationException("Invalid field name $fieldName"); |
| 368 } |
| 369 } |
| 361 | 370 |
| 362 operator ==(x) => x is _NamedField && (name == x.name); | 371 String get name => |
| 372 _name == null ? _name = MirrorSystem.getName(nameSymbol) : _name; |
| 373 |
| 374 operator ==(x) => x is _NamedField && (nameSymbol == x.nameSymbol); |
| 363 int get hashCode => name.hashCode; | 375 int get hashCode => name.hashCode; |
| 364 | 376 |
| 365 /** | 377 /** |
| 366 * Return true if this field is treated as essential state, either because | 378 * Return true if this field is treated as essential state, either because |
| 367 * it is used in the constructor, or because it's been designated | 379 * it is used in the constructor, or because it's been designated |
| 368 * using [setFieldWith]. | 380 * using [setFieldWith]. |
| 369 */ | 381 */ |
| 370 bool get isEssential => super.isEssential || customSetter != null; | 382 bool get isEssential => super.isEssential || customSetter != null; |
| 371 | 383 |
| 372 /** Set the [value] of our field in the given mirrored [object]. */ | 384 /** Set the [value] of our field in the given mirrored [object]. */ |
| 373 void setValue(InstanceMirror object, value) { | 385 void setValue(InstanceMirror object, value) { |
| 374 setter(object, value); | 386 setter(object, value); |
| 375 } | 387 } |
| 376 | 388 |
| 377 valueIn(InstanceMirror mirror) => | 389 valueIn(InstanceMirror mirror) => mirror.getField(nameSymbol).reflectee; |
| 378 deprecatedFutureValue(mirror.getFieldAsync(name)).reflectee; | |
| 379 | 390 |
| 380 /** Return the function to use to set our value. */ | 391 /** Return the function to use to set our value. */ |
| 381 Function get setter => | 392 Function get setter => |
| 382 (customSetter != null) ? customSetter : defaultSetter; | 393 (customSetter != null) ? customSetter : defaultSetter; |
| 383 | 394 |
| 384 /** Return a default setter function. */ | 395 /** The default setter function. */ |
| 385 void defaultSetter(InstanceMirror object, value) { | 396 void defaultSetter(InstanceMirror object, value) { |
| 386 object.setFieldAsync(name, reflect(value)); | 397 object.setField(nameSymbol, value); |
| 387 } | 398 } |
| 388 | 399 |
| 389 String toString() => 'Field($name)'; | 400 String toString() => 'Field($name)'; |
| 390 } | 401 } |
| 391 | 402 |
| 392 /** | 403 /** |
| 393 * This represents a constant value that will be passed as a constructor | 404 * This represents a constant value that will be passed as a constructor |
| 394 * parameter. Rather than having a name it has a constant value. | 405 * parameter. Rather than having a name it has a constant value. |
| 395 */ | 406 */ |
| 396 class _ConstantField extends _Field { | 407 class _ConstantField extends _Field { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 414 get name => value; | 425 get name => value; |
| 415 } | 426 } |
| 416 | 427 |
| 417 /** | 428 /** |
| 418 * The organization of fields in an object can be reasonably complex, so they | 429 * The organization of fields in an object can be reasonably complex, so they |
| 419 * are kept in a separate object, which also has the ability to compute the | 430 * are kept in a separate object, which also has the ability to compute the |
| 420 * default fields to use reflectively. | 431 * default fields to use reflectively. |
| 421 */ | 432 */ |
| 422 class _FieldList extends IterableBase { | 433 class _FieldList extends IterableBase { |
| 423 /** | 434 /** |
| 424 * All of our fields, indexed by name. Note that the names are not | 435 * All of our fields, indexed by name. Note that the names are |
| 425 * necessarily strings. | 436 * typically Symbols, but can also be arbitrary constants. |
| 426 */ | 437 */ |
| 427 Map<dynamic, _Field> allFields = new Map<dynamic, _Field>(); | 438 Map<dynamic, _Field> allFields = new Map<dynamic, _Field>(); |
| 428 | 439 |
| 429 /** | 440 /** |
| 430 * The fields which are used in the constructor. The fields themselves also | 441 * The fields which are used in the constructor. The fields themselves also |
| 431 * know if they are constructor fields or not, but we need to keep this | 442 * know if they are constructor fields or not, but we need to keep this |
| 432 * information here because the order matters. | 443 * information here because the order matters. |
| 433 */ | 444 */ |
| 434 List _constructorFields = const []; | 445 List _constructorFields = const []; |
| 435 | 446 |
| 436 /** The list of fields to exclude if we are computing the list ourselves. */ | 447 /** The list of fields to exclude if we are computing the list ourselves. */ |
| 437 List<String> _excludeFields = const []; | 448 List<Symbol> _excludedFieldNames = const []; |
| 438 | 449 |
| 439 /** The mirror we will use to compute the fields. */ | 450 /** The mirror we will use to compute the fields. */ |
| 440 final ClassMirror mirror; | 451 final ClassMirror mirror; |
| 441 | 452 |
| 442 /** Cached, sorted list of fields. */ | 453 /** Cached, sorted list of fields. */ |
| 443 List<_Field> _contents; | 454 List<_Field> _contents; |
| 444 | 455 |
| 445 /** Should we compute the fields or just use whatever we were given. */ | 456 /** Should we compute the fields or just use whatever we were given. */ |
| 446 bool _shouldFigureOutFields = true; | 457 bool _shouldFigureOutFields = true; |
| 447 | 458 |
| 448 _FieldList(this.mirror); | 459 _FieldList(this.mirror); |
| 449 | 460 |
| 450 /** Look up a field by [name]. */ | 461 /** Look up a field by [name]. */ |
| 451 _Field named(String name) => allFields[name]; | 462 _Field named(name) => allFields[name]; |
| 452 | 463 |
| 453 /** Set the fields to be used in the constructor. */ | 464 /** Set the fields to be used in the constructor. */ |
| 454 set constructorFields(List fieldNames) { | 465 set constructorFields(List fieldNames) { |
| 455 if (fieldNames == null || fieldNames.isEmpty) return; | 466 if (fieldNames == null || fieldNames.isEmpty) return; |
| 456 _constructorFields = []; | 467 _constructorFields = []; |
| 457 for (var each in fieldNames) { | 468 for (var each in fieldNames) { |
| 458 var field = new _Field(each, this)..usedInConstructor = true; | 469 var symbol = _asSymbol(each); |
| 459 allFields[each] = field; | 470 var name = _Field._isReallyAField(symbol, this) ? symbol : each; |
| 471 var field = new _Field(name, this)..usedInConstructor = true; |
| 472 allFields[name] = field; |
| 460 _constructorFields.add(field); | 473 _constructorFields.add(field); |
| 461 } | 474 } |
| 462 invalidate(); | 475 invalidate(); |
| 463 } | 476 } |
| 464 | 477 |
| 465 /** Set the fields that aren't used in the constructor. */ | 478 /** Set the fields that aren't used in the constructor. */ |
| 466 set regular(List<String> fields) { | 479 set regular(List<String> fields) { |
| 467 if (fields == null) return; | 480 if (fields == null) return; |
| 468 _shouldFigureOutFields = false; | 481 _shouldFigureOutFields = false; |
| 469 addAllByName(fields); | 482 addAllByName(fields); |
| 470 } | 483 } |
| 471 | 484 |
| 472 /** Set the fields to be excluded. This is mutually exclusive with setting | 485 /** Set the fields to be excluded. This is mutually exclusive with setting |
| 473 * the regular fields. | 486 * the regular fields. |
| 474 */ | 487 */ |
| 475 set exclude(List<String> fields) { | 488 set exclude(List<String> fields) { |
| 476 // TODO(alanknight): This isn't well tested. | 489 // TODO(alanknight): This isn't well tested. |
| 477 if (fields == null || fields.isEmpty) return; | 490 if (fields == null || fields.isEmpty) return; |
| 478 if (allFields.length > _constructorFields.length) { | 491 if (allFields.length > _constructorFields.length) { |
| 479 throw "You can't specify both excludeFields and regular fields"; | 492 throw "You can't specify both excludeFields and regular fields"; |
| 480 } | 493 } |
| 481 _excludeFields = fields; | 494 _excludedFieldNames = fields.map((x) => new Symbol(x)).toList(); |
| 482 } | 495 } |
| 483 | 496 |
| 484 int get length => allFields.length; | 497 int get length => allFields.length; |
| 485 | 498 |
| 486 /** Add all the fields which aren't on the exclude list. */ | 499 /** Add all the fields which aren't on the exclude list. */ |
| 487 void addAllNotExplicitlyExcluded(Iterable<String> aCollection) { | 500 void addAllNotExplicitlyExcluded(Iterable<String> aCollection) { |
| 488 if (aCollection == null) return; | 501 if (aCollection == null) return; |
| 489 var names = aCollection; | 502 var names = aCollection; |
| 490 names = names.where((x) => !_excludeFields.contains(x)); | 503 names = names.where((x) => !_excludedFieldNames.contains(x)); |
| 491 addAllByName(names); | 504 addAllByName(names); |
| 492 } | 505 } |
| 493 | 506 |
| 494 /** Add all the fields with the given names without any special properties. */ | 507 /** Add all the fields with the given names without any special properties. */ |
| 495 void addAllByName(Iterable<String> names) { | 508 void addAllByName(Iterable<String> names) { |
| 496 for (var each in names) { | 509 for (var each in names) { |
| 497 allFields.putIfAbsent(each, () => new _Field(each, this)); | 510 var symbol = _asSymbol(each); |
| 511 var field = new _Field(symbol, this); |
| 512 allFields.putIfAbsent(symbol, () => new _Field(symbol, this)); |
| 498 } | 513 } |
| 499 invalidate(); | 514 invalidate(); |
| 500 } | 515 } |
| 501 | 516 |
| 502 /** | 517 /** |
| 503 * Fields have been added. In case we had already forced calculation of the | 518 * Fields have been added. In case we had already forced calculation of the |
| 504 * list of contents, re-set it. | 519 * list of contents, re-set it. |
| 505 */ | 520 */ |
| 506 void invalidate() { | 521 void invalidate() { |
| 507 _contents = null; | 522 _contents = null; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 555 * that are listed in the constructor fields. | 570 * that are listed in the constructor fields. |
| 556 */ | 571 */ |
| 557 void figureOutFields() { | 572 void figureOutFields() { |
| 558 Iterable names(Iterable<DeclarationMirror> mirrors) => | 573 Iterable names(Iterable<DeclarationMirror> mirrors) => |
| 559 mirrors.map((each) => each.simpleName).toList(); | 574 mirrors.map((each) => each.simpleName).toList(); |
| 560 | 575 |
| 561 if (!_shouldFigureOutFields || !regularFields().isEmpty) return; | 576 if (!_shouldFigureOutFields || !regularFields().isEmpty) return; |
| 562 var fields = publicFields(mirror); | 577 var fields = publicFields(mirror); |
| 563 var getters = publicGetters(mirror); | 578 var getters = publicGetters(mirror); |
| 564 var gettersWithSetters = getters.where( (each) | 579 var gettersWithSetters = getters.where( (each) |
| 565 => mirror.setters["${each.simpleName}="] != null); | 580 => mirror.setters[ |
| 581 new Symbol("${MirrorSystem.getName(each.simpleName)}=")] != null); |
| 566 var gettersThatMatchConstructor = getters.where((each) | 582 var gettersThatMatchConstructor = getters.where((each) |
| 567 => (named(each.simpleName) != null) && | 583 => (named(each.simpleName) != null) && |
| 568 (named(each.simpleName).usedInConstructor)).toList(); | 584 (named(each.simpleName).usedInConstructor)).toList(); |
| 569 addAllNotExplicitlyExcluded(names(fields)); | 585 addAllNotExplicitlyExcluded(names(fields)); |
| 570 addAllNotExplicitlyExcluded(names(gettersWithSetters)); | 586 addAllNotExplicitlyExcluded(names(gettersWithSetters)); |
| 571 addAllNotExplicitlyExcluded(names(gettersThatMatchConstructor)); | 587 addAllNotExplicitlyExcluded(names(gettersThatMatchConstructor)); |
| 572 } | 588 } |
| 573 | 589 |
| 574 toString() => "FieldList($contents)"; | 590 toString() => "FieldList($contents)"; |
| 575 } | 591 } |
| 576 | 592 |
| 577 /** | 593 /** |
| 578 * Provide a typedef for the setWith argument to setFieldWith. It would | 594 * Provide a typedef for the setWith argument to setFieldWith. It would |
| 579 * be nice if we could put this closer to the definition. | 595 * be nice if we could put this closer to the definition. |
| 580 */ | 596 */ |
| 581 typedef SetWithFunction(InstanceMirror m, object); | 597 typedef SetWithFunction(InstanceMirror m, object); |
| 582 | 598 |
| 583 /** | 599 /** |
| 584 * This represents a constructor that is to be used when re-creating a | 600 * This represents a constructor that is to be used when re-creating a |
| 585 * serialized object. | 601 * serialized object. |
| 586 */ | 602 */ |
| 587 class Constructor { | 603 class Constructor { |
| 588 /** The mirror of the class we construct. */ | 604 /** The mirror of the class we construct. */ |
| 589 final ClassMirror type; | 605 final ClassMirror type; |
| 590 | 606 |
| 591 /** The name of the constructor to use, if not the default constructor.*/ | 607 /** The name of the constructor to use, if not the default constructor.*/ |
| 592 String name; | 608 String name; |
| 609 Symbol nameSymbol; |
| 593 | 610 |
| 594 /** | 611 /** |
| 595 * The indices of the fields used as constructor arguments. We will look | 612 * The indices of the fields used as constructor arguments. We will look |
| 596 * these up in the state by number. These correspond to the index in the | 613 * these up in the state by number. These correspond to the index in the |
| 597 * [contents] of the FieldList, which will be alphabetically sorted. | 614 * [contents] of the FieldList, which will be alphabetically sorted. |
| 598 */ | 615 */ |
| 599 List<int> fieldNumbers; | 616 List<int> fieldNumbers; |
| 600 | 617 |
| 601 /** | 618 /** |
| 602 * Creates a new constructor for the [type] with the constructor named [name] | 619 * Creates a new constructor for the [type] with the constructor named [name] |
| 603 * and the [fieldNumbers] of the constructor fields. | 620 * and the [fieldNumbers] of the constructor fields. |
| 604 */ | 621 */ |
| 605 Constructor(this.type, this.name, this.fieldNumbers) { | 622 Constructor(this.type, this.name, this.fieldNumbers) { |
| 606 if (name == null) name = ''; | 623 if (name == null) name = ''; |
| 624 nameSymbol = new Symbol(name); |
| 607 if (fieldNumbers == null) fieldNumbers = const []; | 625 if (fieldNumbers == null) fieldNumbers = const []; |
| 608 } | 626 } |
| 609 | 627 |
| 610 /** | 628 /** |
| 611 * Find the field values in [state] and pass them to the constructor. | 629 * Find the field values in [state] and pass them to the constructor. |
| 612 * If any of [fieldNumbers] is not an int, then use it as a literal value. | 630 * If any of [fieldNumbers] is not an int, then use it as a literal value. |
| 613 */ | 631 */ |
| 614 constructFrom(state, Reader r) { | 632 constructFrom(state, Reader r) { |
| 615 // TODO(alanknight): Handle named parameters | 633 // TODO(alanknight): Handle named parameters |
| 616 Iterable inflated = fieldNumbers.map( | 634 Iterable inflated = fieldNumbers.map( |
| 617 (x) => (x is int) ? reflect(r.inflateReference(state[x])) : reflect(x)); | 635 (x) => (x is int) ? r.inflateReference(state[x]) : x); |
| 618 var result = type.newInstanceAsync(name, inflated.toList()); | 636 var result; |
| 619 return deprecatedFutureValue(result); | 637 try { |
| 638 result = type.newInstance(nameSymbol, inflated.toList()); |
| 639 } on MirroredError catch (e) { |
| 640 // Mirrored "compile-time" errors do not get treated as exceptions |
| 641 // in the debugger, so explicitly re-throw. Issue dartbug.com/10054. |
| 642 throw e; |
| 643 } |
| 644 return result; |
| 620 } | 645 } |
| 621 } | 646 } |
| 622 | 647 |
| 623 /** | 648 /** |
| 624 * This wraps a map to make it indexable by integer field numbers. It translates | 649 * This wraps a map to make it indexable by integer field numbers. It translates |
| 625 * from the index into a field name and then looks it up in the map. | 650 * from the index into a field name and then looks it up in the map. |
| 626 */ | 651 */ |
| 627 class _MapWrapper { | 652 class _MapWrapper { |
| 628 final _map; | 653 final _map; |
| 629 List fieldList; | 654 List fieldList; |
| 630 _MapWrapper(this.fieldList) : _map = new Map(); | 655 _MapWrapper(this.fieldList) : _map = new Map(); |
| 631 _MapWrapper.fromMap(this._map, this.fieldList); | 656 _MapWrapper.fromMap(this._map, this.fieldList); |
| 632 | 657 |
| 633 operator [](key) => _map[fieldList[key].name]; | 658 operator [](key) => _map[fieldList[key].name]; |
| 634 | 659 |
| 635 operator []=(key, value) { _map[fieldList[key].name] = value; } | 660 operator []=(key, value) { _map[fieldList[key].name] = value; } |
| 636 get length => _map.length; | 661 get length => _map.length; |
| 637 | 662 |
| 638 asMap() => _map; | 663 asMap() => _map; |
| 639 } | 664 } |
| 665 |
| 666 /** |
| 667 * Return a symbol corresponding to [value], which may be a String or a |
| 668 * Symbol. If it is any other type, or if the string is an |
| 669 * invalid symbol, return null; |
| 670 */ |
| 671 _asSymbol(value) { |
| 672 if (value is Symbol) return value; |
| 673 if (value is String) { |
| 674 try { |
| 675 return new Symbol(value); |
| 676 } on ArgumentError { |
| 677 return null; |
| 678 }; |
| 679 } else { |
| 680 return null; |
| 681 } |
| 682 } |
| OLD | NEW |