Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(166)

Unified Diff: pkg/serialization/lib/serialization.dart

Issue 581243002: remove serialization. it's moved to github (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/serialization/README.md ('k') | pkg/serialization/lib/src/basic_rule.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/serialization/lib/serialization.dart
diff --git a/pkg/serialization/lib/serialization.dart b/pkg/serialization/lib/serialization.dart
deleted file mode 100644
index b2d3dce6f835815efabceca0fd35197c94aecb6d..0000000000000000000000000000000000000000
--- a/pkg/serialization/lib/serialization.dart
+++ /dev/null
@@ -1,495 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-/**
- * A general-purpose serialization facility for Dart objects.
- *
- * A [Serialization] is defined in terms of [SerializationRule]s and supports
- * reading and writing to different formats.
- *
- * For information on installing and importing this library, see the
- * [serialization package on pub.dartlang.org]
- * (http://pub.dartlang.org/packages/serialization).
- *
- * ## Setup
- *
- * A simple example of usage is
- *
- * var address = new Address();
- * address.street = 'N 34th';
- * address.city = 'Seattle';
- * var serialization = new Serialization()
- * ..addRuleFor(Address);
- * Map output = serialization.write(address);
- *
- * This creates a new serialization and adds a rule for address objects.
- * Then we ask the [Serialization] to write the address
- * and we get back a Map which is a [json]able representation of the state of
- * the address and related objects. Note that while the output in this case
- * is a [Map], the type will vary depending on which output format we've told
- * the [Serialization] to use.
- *
- * The version above used reflection to automatically identify the public
- * fields of the address object. We can also specify those fields explicitly.
- *
- * var serialization = new Serialization()
- * ..addRuleFor(Address,
- * constructor: "create",
- * constructorFields: ["number", "street"],
- * fields: ["city"]);
- *
- * This rule still uses reflection to access the fields, but does not try to
- * identify which fields to use, but instead uses only the "number" and "street"
- * fields that we specified. We may also want to tell it to identify the
- * fields, but to specifically omit certain fields that we don't want
- * serialized.
- *
- * var serialization = new Serialization()
- * ..addRuleFor(Address,
- * constructor: "",
- * excludeFields: ["other", "stuff"]);
- *
- * ## Writing rules
- *
- * We can also use a completely non-reflective rule to serialize and
- * de-serialize objects. This can be more work, but it does work in
- * dart2js, where mirrors are not yet implemented. We can specify this in two
- * ways. First, we can write our own SerializationRule class that has methods
- * for our Address class.
- *
- * class AddressRule extends CustomRule {
- * bool appliesTo(instance, Writer w) => instance.runtimeType == Address;
- * getState(instance) => [instance.street, instance.city];
- * create(state) => new Address();
- * setState(Address a, List state) {
- * a.street = state[0];
- * a.city = state[1];
- * }
- * }
- *
- * The class needs four different methods. The [CustomRule.appliesTo]
- * method tells us if
- * the rule should be used to write an object. In this example we use a test
- * based on runtimeType. We could also use an "is Address" test, but if Address
- * has subclasses that would find those as well, and we want a separate rule
- * for each. The [CustomRule.getState] method should
- * return all the state of the object that we want to recreate,
- * and should be either a Map or a List. If you want to write to human-readable
- * formats where it's useful to be able to look at the data as a map from
- * field names to values, then it's better to return it as a map. Otherwise it's
- * more efficient to return it as a list. You just need to be sure that the
- * [CustomRule.create] and [CustomRule.setState] methods interpret the data the
- * same way as [CustomRule.getState] does.
- *
- * The [CustomRule.create] method will create the new object and return it. While it's
- * possible to create the object and set all its state in this one method, that
- * increases the likelihood of problems with cycles. So it's better to use the
- * minimum necessary information in [CustomRule.create] and do more of the work
- * in [CustomRule.setState].
- *
- * The other way to do this is not creating a subclass, but by using a
- * [ClosureRule] and giving it functions for how to create
- * the address.
- *
- * addressToMap(a) => {"number" : a.number, "street" : a.street,
- * "city" : a.city};
- * createAddress(Map m) => new Address.create(m["number"], m["street"]);
- * fillInAddress(Address a, Map m) => a.city = m["city"];
- * var serialization = new Serialization()
- * ..addRule(
- * new ClosureRule(anAddress.runtimeType,
- * addressToMap, createAddress, fillInAddress);
- *
- * In this case we have created standalone functions rather than
- * methods in a subclass and we pass them to the constructor of
- * [ClosureRule]. In this case we've also had them use maps rather than
- * lists for the state, but either would work as long as the rule is
- * consistent with the representation it uses. We pass it the runtimeType
- * of the object, and functions equivalent to the methods on [CustomRule]
- *
- * ## Constant values
- *
- * There are cases where the constructor needs values that we can't easily get
- * from the serialized object. For example, we may just want to pass null, or a
- * constant value. To support this, we can specify as constructor fields
- * values that aren't field names. If any value isn't a String, or is a string
- * that doesn't correspond to a field name, it will be
- * treated as a constant and passed unaltered to the constructor.
- *
- * In some cases a non-constructor field should not be set using field
- * access or a setter, but should be done by calling a method. For example, it
- * may not be possible to set a List field "foo", and you need to call an
- * addFoo() method for each entry in the list. In these cases, if you are using
- * a BasicRule for the object you can call the setFieldWith() method.
- *
- * s..addRuleFor(FooHolder).setFieldWith("foo",
- * (parent, value) => for (var each in value) parent.addFoo(value));
- *
- * ## Writing
- *
- * To write objects, we use the write() method.
- *
- * var output = serialization.write(someObject);
- *
- * By default this uses a representation in which objects are represented as
- * maps keyed by field name, but in which references between objects have been
- * converted into Reference objects. This is then typically encoded as
- * a [json] string, but can also be used in other ways, e.g. sent to another
- * isolate.
- *
- * We can write objects in different formats by passing a [Format] object to
- * the [Serialization.write] method or by getting a [Writer] object.
- * The available formats
- * include the default, a simple "flat" format that doesn't include field names,
- * and a simple JSON format that produces output more suitable for talking to
- * services that expect JSON in a predefined format. Examples of these are
- *
- * Map output = serialization.write(address, new SimpleMapFormat());
- * List output = serialization.write(address, new SimpleFlatFormat());
- * var output = serialization.write(address, new SimpleJsonFormat());
- * Or, using a [Writer] explicitly
- * var writer = serialization.newWriter(new SimpleFlatFormat());
- * List output = writer.write(address);
- *
- * These representations are not yet considered stable.
- *
- * ## Reading
- *
- * To read objects, the corresponding [Serialization.read] method can be used.
- *
- * Address input = serialization.read(input);
- *
- * When reading, the serialization instance doing the reading must be configured
- * with compatible rules to the one doing the writing. It's possible for the
- * rules to be different, but they need to be able to read the same
- * representation. For most practical purposes right now they should be the
- * same. The simplest way to achieve this is by having the serialization
- * variable [Serialization.selfDescribing] be true. In that case the rules
- * themselves are also
- * stored along with the serialized data, and can be read back on the receiving
- * end. Note that this may not work for all rules or all formats. The
- * [Serialization.selfDescribing] variable is true by default, but the
- * [SimpleJsonFormat] does not support it, since the point is to provide a
- * representation in a form
- * other services might expect. Using CustomRule or ClosureRule also does not
- * yet work with the [Serialization.selfDescribing] variable.
- *
- * ## Named objects
- *
- * When reading, some object references should not be serialized, but should be
- * connected up to other instances on the receiving side. A notable example of
- * this is when serialization rules have been stored. Instances of BasicRule
- * take a [ClassMirror] in their constructor, and we cannot serialize those. So
- * when we read the rules, we must provide a Map<String, Object> which maps from
- * the simple name of classes we are interested in to a [ClassMirror]. This can
- * be provided either in the [Serialization.namedObjects],
- * or as an additional parameter to the reading and writing methods on the
- * [Reader] or [Writer] respectively.
- *
- * new Serialization()
- * ..addRuleFor(Person, constructorFields: ["name"])
- * ..namedObjects['Person'] = reflect(new Person()).type;
- */
-library serialization;
-
-import 'src/mirrors_helpers.dart';
-import 'src/serialization_helpers.dart';
-import 'dart:collection';
-
-part 'src/reader_writer.dart';
-part 'src/serialization_rule.dart';
-part 'src/basic_rule.dart';
-part 'src/format.dart';
-
-/**
- * This class defines a particular serialization scheme, in terms of
- * [SerializationRule] instances, and supports reading and writing them.
- * See library comment for examples of usage.
- */
-class Serialization {
- final List<SerializationRule> _rules;
-
- /**
- * The serialization is controlled by the list of Serialization rules. These
- * are most commonly added via [addRuleFor].
- */
- final UnmodifiableListView<SerializationRule> rules;
-
- /**
- * When reading, we may need to resolve references to existing objects in
- * the system. The right action may not be to create a new instance of
- * something, but rather to find an existing instance and connect to it.
- * For example, if we have are serializing an Email message and it has a
- * link to the owning account, it may not be appropriate to try and serialize
- * the account. Instead we should just connect the de-serialized message
- * object to the account object that already exists there.
- */
- Map<String, dynamic> namedObjects = {};
-
- /**
- * When we write out data using this serialization, should we also write
- * out a description of the rules. This is on by default unless using
- * CustomRule subclasses, in which case it requires additional setup and
- * is off by default.
- */
- bool _selfDescribing;
-
- /**
- * When we write out data using this serialization, should we also write
- * out a description of the rules. This is on by default unless using
- * CustomRule subclasses, in which case it requires additional setup and
- * is off by default.
- */
- bool get selfDescribing {
- // TODO(alanknight): Should this be moved to the format?
- // TODO(alanknight): Allow self-describing in the presence of CustomRule.
- // TODO(alanknight): Don't do duplicate work creating a writer and
- // serialization here and then re-creating when we actually serialize.
- if (_selfDescribing != null) return _selfDescribing;
- var meta = ruleSerialization();
- var w = meta.newWriter();
- _selfDescribing = !rules.any((rule) =>
- meta.rulesFor(rule, w, create: false).isEmpty);
- return _selfDescribing;
- }
-
- /**
- * When we write out data using this serialization, should we also write
- * out a description of the rules. This is on by default unless using
- * CustomRule subclasses, in which case it requires additional setup and
- * is off by default.
- */
- void set selfDescribing(bool value) {
- _selfDescribing = value;
- }
-
- /**
- * Creates a new serialization with a default set of rules for primitives
- * and lists.
- */
- factory Serialization() =>
- new Serialization.blank()
- ..addDefaultRules();
-
- /**
- * Creates a new serialization with no default rules at all. The most common
- * use for this is if we are reading self-describing serialized data and
- * will populate the rules from that data.
- */
- factory Serialization.blank()
- => new Serialization._(new List<SerializationRule>());
-
- Serialization._(List<SerializationRule> rules) :
- this._rules = rules,
- this.rules = new UnmodifiableListView(rules);
-
- /**
- * Create a [BasicRule] rule for [instanceOrType]. Normally this will be
- * a type, but for backward compatibilty we also allow you to pass an
- * instance (except an instance of Type), and the rule will be created
- * for its runtimeType. Optionally
- * allows specifying a [constructor] name, the list of [constructorFields],
- * and the list of [fields] not used in the constructor. Returns the new
- * rule. Note that [BasicRule] uses reflection, and so will not work with the
- * current state of dartj2s. If you need to run there, consider using
- * [CustomRule] instead.
- *
- * If the optional parameters aren't specified, the default constructor will
- * be used, and the list of fields will be computed. Alternatively, you can
- * omit [fields] and provide [excludeFields], which will then compute the
- * list of fields specifically excluding those listed.
- *
- * The fields can be actual public fields, but can also be getter/setter
- * pairs or getters whose value is provided in the constructor. For the
- * [constructorFields] they can also be arbitrary objects. Anything that is
- * not a String will be treated as a constant value to be used in any
- * construction of these objects.
- *
- * If the list of fields is computed, fields from the superclass will be
- * included. However, each subclass needs its own rule, since the constructors
- * are not inherited, and so may need to be specified separately for each
- * subclass.
- */
- BasicRule addRuleFor(
- instanceOrType,
- {String constructor,
- List constructorFields,
- List<String> fields,
- List<String> excludeFields}) {
-
- var rule = new BasicRule(
- turnInstanceIntoSomethingWeCanUse(
- instanceOrType),
- constructor, constructorFields, fields, excludeFields);
- addRule(rule);
- return rule;
- }
-
- /** Set up the default rules, for lists and primitives. */
- void addDefaultRules() {
- addRule(new PrimitiveRule());
- addRule(new ListRule());
- // Both these rules apply to lists, so unless otherwise indicated,
- // it will always find the first one.
- addRule(new ListRuleEssential());
- addRule(new MapRule());
- addRule(new SymbolRule());
- addRule(new DateTimeRule());
- }
-
- /**
- * Add a new SerializationRule [rule]. The addRuleFor method will probably
- * handle most simple cases, but for adding an arbitrary rule, including
- * a SerializationRule subclass which you have created, you can use this
- * method.
- */
- void addRule(SerializationRule rule) {
- rule.number = _rules.length;
- _rules.add(rule);
- }
-
- /**
- * This writes out an object graph rooted at [object] and returns the result.
- * The [format] parameter determines the form of the result. The default
- * format is [SimpleMapFormat] and returns a Map.
- */
- write(Object object, {Format format}) {
- return newWriter(format).write(object);
- }
-
- /**
- * Return a new [Writer] object for this serialization. This is useful if you
- * want to do something more complex with the writer than just returning
- * the final result.
- */
- Writer newWriter([Format format]) => new Writer(this, format);
-
- /**
- * Read the serialized data from [input] and return the root object
- * from the result. The [input] can be of any type that the [Format]
- * reads/writes, but normally will be a [List], [Map], or a simple type.
- * The [format] parameter determines the form of the result. The default
- * format is [SimpleMapFormat] and expects a Map as input.
- * If there are objects that need to be resolved
- * in the current context, they should be provided in [externals] as a
- * Map from names to values. In particular, in the current implementation
- * any class mirrors needed should be provided in [externals] using the
- * class name as a key. In addition to the [externals] map provided here,
- * values will be looked up in the [namedObjects] map.
- */
- read(input, {Format format, Map externals: const {}}) {
- return newReader(format).read(input, externals);
- }
-
- /**
- * Return a new [Reader] object for this serialization. This is useful if
- * you want to do something more complex with the reader than just returning
- * the final result.
- */
- Reader newReader([Format format]) => new Reader(this, format);
-
- /**
- * Return the list of SerializationRule that apply to [object]. For
- * internal use, but public because it's used in testing.
- */
- Iterable<SerializationRule> rulesFor(object, Writer w, {create : true}) {
- // This has a couple of edge cases.
- // 1) The owning object may have indicated we should use a different
- // rule than the default.
- // 2) We may not have a rule, in which case we lazily create a BasicRule.
- // 3) Rules are allowed to say mustBePrimary, meaning that they can be used
- // iff no other rule was chosen first.
- // TODO(alanknight): Can the mustBePrimary mechanism be removed or changed.
- // It adds an order dependency to the rules, and is messy. Reconsider in the
- // light of a more general mechanism for multiple rules per object.
- // TODO(alanknight): Finding which rules apply seems likely to be a
- // bottleneck, particularly with the current reflective implementation.
- // Consider how to improve it. e.g. cache the list of rules by class. But
- // be careful of issues like rules which have arbitrary predicates. Or
- // consider having the arbitrary predicates be secondary to an initial
- // class-based lookup mechanism.
- var target, candidateRules;
- if (object is DesignatedRuleForObject) {
- target = object.target;
- candidateRules = object.possibleRules(rules);
- } else {
- target = object;
- candidateRules = rules;
- }
- Iterable applicable = candidateRules.where(
- (each) => each.appliesTo(target, w));
-
- if (applicable.isEmpty) {
- return create ? [addRuleFor(target)] : applicable;
- }
-
- if (applicable.length == 1) return applicable;
- var first = applicable.first;
- var finalRules = applicable.where(
- (x) => !x.mustBePrimary || (x == first));
-
- if (finalRules.isEmpty) throw new SerializationException(
- 'No valid rule found for object $object');
- return finalRules;
- }
-
- /**
- * Create a Serialization for serializing SerializationRules. This is used
- * to save the rules in a self-describing format along with the data.
- * If there are new rule classes created, they will need to be described
- * here.
- */
- Serialization ruleSerialization() {
- // TODO(alanknight): There's an extensibility issue here with new rules.
- // TODO(alanknight): How to handle rules with closures? They have to
- // exist on the other side, but we might be able to hook them up by name,
- // or we might just be able to validate that they're correctly set up
- // on the other side.
-
- var meta = new Serialization()
- ..selfDescribing = false
- ..addRuleFor(ListRule)
- ..addRuleFor(MapRule)
- ..addRuleFor(PrimitiveRule)
- ..addRuleFor(ListRuleEssential)
- ..addRuleFor(BasicRule,
- constructorFields: ['type',
- 'constructorName',
- 'constructorFields', 'regularFields', []],
- fields: [])
- ..addRule(new NamedObjectRule())
- ..addRule(new MirrorRule())
- ..addRuleFor(MirrorRule)
- ..addRuleFor(SymbolRule)
- ..addRuleFor(DateTimeRule);
- meta.namedObjects = namedObjects;
- return meta;
- }
-
- /** Return true if our [namedObjects] collection has an entry for [object].*/
- bool _hasNameFor(object) {
- var sentinel = const _Sentinel();
- return _nameFor(object, () => sentinel) != sentinel;
- }
-
- /**
- * Return the name we have for [object] in our [namedObjects] collection or
- * the result of evaluating [ifAbsent] if there is no entry.
- */
- _nameFor(object, [ifAbsent]) {
- for (var key in namedObjects.keys) {
- if (identical(namedObjects[key], object)) return key;
- }
- return ifAbsent == null ? null : ifAbsent();
- }
-}
-
-/**
- * An exception class for errors during serialization.
- */
-class SerializationException implements Exception {
- final String message;
- const SerializationException(this.message);
- String toString() => "SerializationException($message)";
-}
« no previous file with comments | « pkg/serialization/README.md ('k') | pkg/serialization/lib/src/basic_rule.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698