| Index: sdk/lib/json/json.dart
|
| diff --git a/sdk/lib/json/json.dart b/sdk/lib/json/json.dart
|
| index 114feea544c6ff11cfefac09ae8f5d2a5a6fb866..ba9b7ac89cfb2f4d5b92596c3c066641eb0c4e0f 100644
|
| --- a/sdk/lib/json/json.dart
|
| +++ b/sdk/lib/json/json.dart
|
| @@ -11,6 +11,7 @@ library dart.json;
|
|
|
| import "dart:convert";
|
| import "dart:_collection-dev" show deprecated;
|
| +import "dart:collection" show HashSet;
|
| export "dart:convert" show JsonUnsupportedObjectError, JsonCyclicError;
|
|
|
| // JSON parsing and serialization.
|
| @@ -51,28 +52,31 @@ parse(String json, [reviver(var key, var value)]) {
|
| * For [List], the elements must all be serializable.
|
| * For [Map], the keys must be [String] and the values must be serializable.
|
| *
|
| - * If a value is any other type is attempted serialized, a "toJson()" method
|
| - * is invoked on the object and the result, which must be a directly
|
| - * serializable value, is serialized instead of the original value.
|
| + * If a value is any other type is attempted serialized, the [toEncodable]
|
| + * method is called with the object as argument, and the result, which must be a
|
| + * directly serializable value, is serialized instead of the original value.
|
| + * If [toEncodable] is omitted, the default is to call `object.toJson()` on the
|
| + * object.
|
| *
|
| - * If the object does not support this method, throws, or returns a
|
| - * value that is not directly serializable, a [JsonUnsupportedObjectError]
|
| - * exception is thrown. If the call throws (including the case where there
|
| - * is no nullary "toJson" method, the error is caught and stored in the
|
| + * If the conversion throws, or returns a value that is not directly
|
| + * serializable, a [JsonUnsupportedObjectError] exception is thrown.
|
| + * If the call throws (including the case where there
|
| + * is no nullary "toJson" method), the error is caught and stored in the
|
| * [JsonUnsupportedObjectError]'s [:cause:] field.
|
| *
|
| * If a [List] or [Map] contains a reference to itself, directly or through
|
| * other lists or maps, it cannot be serialized and a [JsonCyclicError] is
|
| * thrown.
|
| *
|
| - * Json Objects should not change during serialization.
|
| + * The objects being serialized should not change during serialization.
|
| * If an object is serialized more than once, [stringify] is allowed to cache
|
| * the JSON text for it. I.e., if an object changes after it is first
|
| * serialized, the new values may or may not be reflected in the result.
|
| */
|
| @deprecated
|
| -String stringify(Object object) {
|
| - return _JsonStringifier.stringify(object);
|
| +String stringify(Object object, [toEncodable(object)]) {
|
| + if (toEncodable == null) toEncodable = _defaultToEncodable;
|
| + return _JsonStringifier.stringify(object, toEncodable);
|
| }
|
|
|
| /**
|
| @@ -87,8 +91,9 @@ String stringify(Object object) {
|
| * [output], but it won't contain valid JSON text.
|
| */
|
| @deprecated
|
| -void printOn(Object object, StringSink output) {
|
| - return _JsonStringifier.printOn(object, output);
|
| +void printOn(Object object, StringSink output, [ toEncodable(object) ]) {
|
| + if (toEncodable == null) toEncodable = _defaultToEncodable;
|
| + return _JsonStringifier.printOn(object, output, toEncodable);
|
| }
|
|
|
| //// Implementation ///////////////////////////////////////////////////////////
|
| @@ -643,22 +648,25 @@ class JsonParser {
|
| }
|
| }
|
|
|
| +Object _defaultToEncodable(object) => object.toJson();
|
|
|
| class _JsonStringifier {
|
| - StringSink sink;
|
| - List<Object> seen; // TODO: that should be identity set.
|
| + final Function toEncodable;
|
| + final StringSink sink;
|
| + final Set<Object> seen;
|
|
|
| - _JsonStringifier(this.sink) : seen = [];
|
| + _JsonStringifier(this.sink, this.toEncodable)
|
| + : this.seen = new HashSet.identity();
|
|
|
| - static String stringify(final object) {
|
| + static String stringify(final object, toEncodable(object)) {
|
| StringBuffer output = new StringBuffer();
|
| - _JsonStringifier stringifier = new _JsonStringifier(output);
|
| + _JsonStringifier stringifier = new _JsonStringifier(output, toEncodable);
|
| stringifier.stringifyValue(object);
|
| return output.toString();
|
| }
|
|
|
| - static void printOn(final object, StringSink output) {
|
| - _JsonStringifier stringifier = new _JsonStringifier(output);
|
| + static void printOn(final object, StringSink output, toEncodable(object)) {
|
| + _JsonStringifier stringifier = new _JsonStringifier(output, toEncodable);
|
| stringifier.stringifyValue(object);
|
| }
|
|
|
| @@ -715,11 +723,8 @@ class _JsonStringifier {
|
| }
|
|
|
| void checkCycle(final object) {
|
| - // TODO: use Iterables.
|
| - for (int i = 0; i < seen.length; i++) {
|
| - if (identical(seen[i], object)) {
|
| - throw new JsonCyclicError(object);
|
| - }
|
| + if (seen.contains(object)) {
|
| + throw new JsonCyclicError(object);
|
| }
|
| seen.add(object);
|
| }
|
| @@ -731,11 +736,11 @@ class _JsonStringifier {
|
| if (!stringifyJsonValue(object)) {
|
| checkCycle(object);
|
| try {
|
| - var customJson = object.toJson();
|
| + var customJson = toEncodable(object);
|
| if (!stringifyJsonValue(customJson)) {
|
| throw new JsonUnsupportedObjectError(object);
|
| }
|
| - seen.removeLast();
|
| + seen.remove(object);
|
| } catch (e) {
|
| throw new JsonUnsupportedObjectError(object, cause: e);
|
| }
|
| @@ -780,7 +785,7 @@ class _JsonStringifier {
|
| }
|
| }
|
| sink.write(']');
|
| - seen.removeLast();
|
| + seen.remove(object);
|
| return true;
|
| } else if (object is Map) {
|
| checkCycle(object);
|
| @@ -799,7 +804,7 @@ class _JsonStringifier {
|
| first = false;
|
| });
|
| sink.write('}');
|
| - seen.removeLast();
|
| + seen.remove(object);
|
| return true;
|
| } else {
|
| return false;
|
|
|