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

Side by Side Diff: sdk/lib/json/json.dart

Issue 25548010: Make JSON encoder take extra function argument to use instead of toJson calls. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Rename convert function to "toEncodable". Created 7 years, 2 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « sdk/lib/convert/json.dart ('k') | tests/json/json_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 * Utilities for encoding and decoding JSON (JavaScript Object Notation) data. 6 * Utilities for encoding and decoding JSON (JavaScript Object Notation) data.
7 */ 7 */
8 8
9 @deprecated 9 @deprecated
10 library dart.json; 10 library dart.json;
11 11
12 import "dart:convert"; 12 import "dart:convert";
13 import "dart:_collection-dev" show deprecated; 13 import "dart:_collection-dev" show deprecated;
14 import "dart:collection" show HashSet;
14 export "dart:convert" show JsonUnsupportedObjectError, JsonCyclicError; 15 export "dart:convert" show JsonUnsupportedObjectError, JsonCyclicError;
15 16
16 // JSON parsing and serialization. 17 // JSON parsing and serialization.
17 18
18 /** 19 /**
19 * *DEPRECATED* Use `dart:convert JSON.decode` instead. 20 * *DEPRECATED* Use `dart:convert JSON.decode` instead.
20 * 21 *
21 * Parses [json] and build the corresponding parsed JSON value. 22 * Parses [json] and build the corresponding parsed JSON value.
22 * 23 *
23 * Parsed JSON values are of the types [num], [String], [bool], [Null], 24 * Parsed JSON values are of the types [num], [String], [bool], [Null],
(...skipping 20 matching lines...) Expand all
44 /** 45 /**
45 * *DEPRECATED* Use `dart:convert JSON.encode` instead. 46 * *DEPRECATED* Use `dart:convert JSON.encode` instead.
46 * 47 *
47 * Serializes [object] into a JSON string. 48 * Serializes [object] into a JSON string.
48 * 49 *
49 * Directly serializable values are [num], [String], [bool], and [Null], as well 50 * Directly serializable values are [num], [String], [bool], and [Null], as well
50 * as some [List] and [Map] values. 51 * as some [List] and [Map] values.
51 * For [List], the elements must all be serializable. 52 * For [List], the elements must all be serializable.
52 * For [Map], the keys must be [String] and the values must be serializable. 53 * For [Map], the keys must be [String] and the values must be serializable.
53 * 54 *
54 * If a value is any other type is attempted serialized, a "toJson()" method 55 * If a value is any other type is attempted serialized, the [toEncodable]
55 * is invoked on the object and the result, which must be a directly 56 * method is called with the object as argument, and the result, which must be a
56 * serializable value, is serialized instead of the original value. 57 * directly serializable value, is serialized instead of the original value.
58 * If [toEncodable] is omitted, the default is to call `object.toJson()` on the
59 * object.
57 * 60 *
58 * If the object does not support this method, throws, or returns a 61 * If the conversion throws, or returns a value that is not directly
59 * value that is not directly serializable, a [JsonUnsupportedObjectError] 62 * serializable, a [JsonUnsupportedObjectError] exception is thrown.
60 * exception is thrown. If the call throws (including the case where there 63 * If the call throws (including the case where there
61 * is no nullary "toJson" method, the error is caught and stored in the 64 * is no nullary "toJson" method), the error is caught and stored in the
62 * [JsonUnsupportedObjectError]'s [:cause:] field. 65 * [JsonUnsupportedObjectError]'s [:cause:] field.
63 * 66 *
64 * If a [List] or [Map] contains a reference to itself, directly or through 67 * If a [List] or [Map] contains a reference to itself, directly or through
65 * other lists or maps, it cannot be serialized and a [JsonCyclicError] is 68 * other lists or maps, it cannot be serialized and a [JsonCyclicError] is
66 * thrown. 69 * thrown.
67 * 70 *
68 * Json Objects should not change during serialization. 71 * The objects being serialized should not change during serialization.
69 * If an object is serialized more than once, [stringify] is allowed to cache 72 * If an object is serialized more than once, [stringify] is allowed to cache
70 * the JSON text for it. I.e., if an object changes after it is first 73 * the JSON text for it. I.e., if an object changes after it is first
71 * serialized, the new values may or may not be reflected in the result. 74 * serialized, the new values may or may not be reflected in the result.
72 */ 75 */
73 @deprecated 76 @deprecated
74 String stringify(Object object) { 77 String stringify(Object object, [toEncodable(object)]) {
75 return _JsonStringifier.stringify(object); 78 if (toEncodable == null) toEncodable = _defaultToEncodable;
79 return _JsonStringifier.stringify(object, toEncodable);
76 } 80 }
77 81
78 /** 82 /**
79 * *DEPRECATED* Use `package:json/json.dart` or `dart:convert` instead. 83 * *DEPRECATED* Use `package:json/json.dart` or `dart:convert` instead.
80 * 84 *
81 * Serializes [object] into [output] stream. 85 * Serializes [object] into [output] stream.
82 * 86 *
83 * Performs the same operations as [stringify] but outputs the resulting 87 * Performs the same operations as [stringify] but outputs the resulting
84 * string to an existing [StringSink] instead of creating a new [String]. 88 * string to an existing [StringSink] instead of creating a new [String].
85 * 89 *
86 * If serialization fails by throwing, some data might have been added to 90 * If serialization fails by throwing, some data might have been added to
87 * [output], but it won't contain valid JSON text. 91 * [output], but it won't contain valid JSON text.
88 */ 92 */
89 @deprecated 93 @deprecated
90 void printOn(Object object, StringSink output) { 94 void printOn(Object object, StringSink output, [ toEncodable(object) ]) {
91 return _JsonStringifier.printOn(object, output); 95 if (toEncodable == null) toEncodable = _defaultToEncodable;
96 return _JsonStringifier.printOn(object, output, toEncodable);
92 } 97 }
93 98
94 //// Implementation /////////////////////////////////////////////////////////// 99 //// Implementation ///////////////////////////////////////////////////////////
95 100
96 // Simple API for JSON parsing. 101 // Simple API for JSON parsing.
97 102
98 /// *DEPRECATED* Use `package:json/json.dart` instead. 103 /// *DEPRECATED* Use `package:json/json.dart` instead.
99 @deprecated 104 @deprecated
100 abstract class JsonListener { 105 abstract class JsonListener {
101 void handleString(String value) {} 106 void handleString(String value) {}
(...skipping 534 matching lines...) Expand 10 before | Expand all | Expand 10 after
636 int sliceEnd = position + 20; 641 int sliceEnd = position + 20;
637 if (sliceEnd > source.length) { 642 if (sliceEnd > source.length) {
638 slice = "'${source.substring(position)}'"; 643 slice = "'${source.substring(position)}'";
639 } else { 644 } else {
640 slice = "'${source.substring(position, sliceEnd)}...'"; 645 slice = "'${source.substring(position, sliceEnd)}...'";
641 } 646 }
642 throw new FormatException("Unexpected character at $position: $slice"); 647 throw new FormatException("Unexpected character at $position: $slice");
643 } 648 }
644 } 649 }
645 650
651 Object _defaultToEncodable(object) => object.toJson();
646 652
647 class _JsonStringifier { 653 class _JsonStringifier {
648 StringSink sink; 654 final Function toEncodable;
649 List<Object> seen; // TODO: that should be identity set. 655 final StringSink sink;
656 final Set<Object> seen;
650 657
651 _JsonStringifier(this.sink) : seen = []; 658 _JsonStringifier(this.sink, this.toEncodable)
659 : this.seen = new HashSet.identity();
652 660
653 static String stringify(final object) { 661 static String stringify(final object, toEncodable(object)) {
654 StringBuffer output = new StringBuffer(); 662 StringBuffer output = new StringBuffer();
655 _JsonStringifier stringifier = new _JsonStringifier(output); 663 _JsonStringifier stringifier = new _JsonStringifier(output, toEncodable);
656 stringifier.stringifyValue(object); 664 stringifier.stringifyValue(object);
657 return output.toString(); 665 return output.toString();
658 } 666 }
659 667
660 static void printOn(final object, StringSink output) { 668 static void printOn(final object, StringSink output, toEncodable(object)) {
661 _JsonStringifier stringifier = new _JsonStringifier(output); 669 _JsonStringifier stringifier = new _JsonStringifier(output, toEncodable);
662 stringifier.stringifyValue(object); 670 stringifier.stringifyValue(object);
663 } 671 }
664 672
665 static String numberToString(num x) { 673 static String numberToString(num x) {
666 return x.toString(); 674 return x.toString();
667 } 675 }
668 676
669 // ('0' + x) or ('a' + x - 10) 677 // ('0' + x) or ('a' + x - 10)
670 static int hexDigit(int x) => x < 10 ? 48 + x : 87 + x; 678 static int hexDigit(int x) => x < 10 ? 48 + x : 87 + x;
671 679
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
708 charCodes.add(JsonParser.BACKSLASH); 716 charCodes.add(JsonParser.BACKSLASH);
709 charCodes.add(charCode); 717 charCodes.add(charCode);
710 } else { 718 } else {
711 charCodes.add(charCode); 719 charCodes.add(charCode);
712 } 720 }
713 } 721 }
714 sb.write(needsEscape ? new String.fromCharCodes(charCodes) : s); 722 sb.write(needsEscape ? new String.fromCharCodes(charCodes) : s);
715 } 723 }
716 724
717 void checkCycle(final object) { 725 void checkCycle(final object) {
718 // TODO: use Iterables. 726 if (seen.contains(object)) {
719 for (int i = 0; i < seen.length; i++) { 727 throw new JsonCyclicError(object);
720 if (identical(seen[i], object)) {
721 throw new JsonCyclicError(object);
722 }
723 } 728 }
724 seen.add(object); 729 seen.add(object);
725 } 730 }
726 731
727 void stringifyValue(final object) { 732 void stringifyValue(final object) {
728 // Tries stringifying object directly. If it's not a simple value, List or 733 // Tries stringifying object directly. If it's not a simple value, List or
729 // Map, call toJson() to get a custom representation and try serializing 734 // Map, call toJson() to get a custom representation and try serializing
730 // that. 735 // that.
731 if (!stringifyJsonValue(object)) { 736 if (!stringifyJsonValue(object)) {
732 checkCycle(object); 737 checkCycle(object);
733 try { 738 try {
734 var customJson = object.toJson(); 739 var customJson = toEncodable(object);
735 if (!stringifyJsonValue(customJson)) { 740 if (!stringifyJsonValue(customJson)) {
736 throw new JsonUnsupportedObjectError(object); 741 throw new JsonUnsupportedObjectError(object);
737 } 742 }
738 seen.removeLast(); 743 seen.remove(object);
739 } catch (e) { 744 } catch (e) {
740 throw new JsonUnsupportedObjectError(object, cause: e); 745 throw new JsonUnsupportedObjectError(object, cause: e);
741 } 746 }
742 } 747 }
743 } 748 }
744 749
745 /** 750 /**
746 * Serializes a [num], [String], [bool], [Null], [List] or [Map] value. 751 * Serializes a [num], [String], [bool], [Null], [List] or [Map] value.
747 * 752 *
748 * Returns true if the value is one of these types, and false if not. 753 * Returns true if the value is one of these types, and false if not.
(...skipping 24 matching lines...) Expand all
773 sink.write('['); 778 sink.write('[');
774 if (a.length > 0) { 779 if (a.length > 0) {
775 stringifyValue(a[0]); 780 stringifyValue(a[0]);
776 // TODO: switch to Iterables. 781 // TODO: switch to Iterables.
777 for (int i = 1; i < a.length; i++) { 782 for (int i = 1; i < a.length; i++) {
778 sink.write(','); 783 sink.write(',');
779 stringifyValue(a[i]); 784 stringifyValue(a[i]);
780 } 785 }
781 } 786 }
782 sink.write(']'); 787 sink.write(']');
783 seen.removeLast(); 788 seen.remove(object);
784 return true; 789 return true;
785 } else if (object is Map) { 790 } else if (object is Map) {
786 checkCycle(object); 791 checkCycle(object);
787 Map<String, Object> m = object; 792 Map<String, Object> m = object;
788 sink.write('{'); 793 sink.write('{');
789 bool first = true; 794 bool first = true;
790 m.forEach((String key, Object value) { 795 m.forEach((String key, Object value) {
791 if (!first) { 796 if (!first) {
792 sink.write(',"'); 797 sink.write(',"');
793 } else { 798 } else {
794 sink.write('"'); 799 sink.write('"');
795 } 800 }
796 escape(sink, key); 801 escape(sink, key);
797 sink.write('":'); 802 sink.write('":');
798 stringifyValue(value); 803 stringifyValue(value);
799 first = false; 804 first = false;
800 }); 805 });
801 sink.write('}'); 806 sink.write('}');
802 seen.removeLast(); 807 seen.remove(object);
803 return true; 808 return true;
804 } else { 809 } else {
805 return false; 810 return false;
806 } 811 }
807 } 812 }
808 } 813 }
OLDNEW
« no previous file with comments | « sdk/lib/convert/json.dart ('k') | tests/json/json_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698