|
5 | 5 | library built_json; |
6 | 6 |
|
7 | 7 | import 'src/bool_serializer.dart'; |
| 8 | +import 'src/built_json_serializers.dart'; |
8 | 9 | import 'src/built_list_serializer.dart'; |
9 | 10 | import 'src/built_map_serializer.dart'; |
10 | 11 | import 'src/built_set_serializer.dart'; |
11 | 12 | import 'src/double_serializer.dart'; |
12 | 13 | import 'src/int_serializer.dart'; |
13 | 14 | import 'src/string_serializer.dart'; |
14 | 15 |
|
15 | | -/// Serializes a single class. |
16 | | -/// |
17 | | -/// See <https://github.com/google/built_json.dart/tree/master/example> |
18 | | -abstract class BuiltJsonSerializer<T> { |
19 | | - Type get type; |
20 | | - String get typeName; |
21 | | - |
22 | | - Object serialize(BuiltJsonSerializers builtJsonSerializers, T object, |
23 | | - {String expectedType}); |
24 | | - T deserialize(BuiltJsonSerializers builtJsonSerializers, Object object, |
25 | | - {String expectedType}); |
26 | | -} |
| 16 | +export 'package:built_collection/built_collection.dart' show BuiltList; |
27 | 17 |
|
28 | | -/// Serializes all transitive dependencies of a class. |
| 18 | +/// Serializes all known classes. |
29 | 19 | /// |
30 | 20 | /// See <https://github.com/google/built_json.dart/tree/master/example> |
31 | | -// TODO(davidmorgan): make immutable. |
32 | | -class BuiltJsonSerializers { |
33 | | - Map<String, String> _deobfuscatedNames = <String, String>{}; |
34 | | - Map<String, BuiltJsonSerializer> _serializersByName = |
35 | | - <String, BuiltJsonSerializer>{}; |
36 | | - |
37 | | - BuiltJsonSerializers() { |
38 | | - add(new BoolSerializer()); |
39 | | - add(new DoubleSerializer()); |
40 | | - add(new IntSerializer()); |
41 | | - add(new StringSerializer()); |
42 | | - |
43 | | - add(new BuiltListSerializer()); |
44 | | - add(new BuiltMapSerializer()); |
45 | | - add(new BuiltSetSerializer()); |
| 21 | +abstract class Serializers { |
| 22 | + /// Default [Serializers] that can serialize primitives and collections. |
| 23 | + /// |
| 24 | + /// Use [toBuilder] to add more serializers. |
| 25 | + factory Serializers() { |
| 26 | + return (new SerializersBuilder() |
| 27 | + ..add(new BoolSerializer()) |
| 28 | + ..add(new BuiltListSerializer()) |
| 29 | + ..add(new BuiltMapSerializer()) |
| 30 | + ..add(new BuiltSetSerializer()) |
| 31 | + ..add(new DoubleSerializer()) |
| 32 | + ..add(new IntSerializer()) |
| 33 | + ..add(new StringSerializer())).build(); |
46 | 34 | } |
47 | 35 |
|
48 | | - void addAll(BuiltJsonSerializers builtJsonSerializers) { |
49 | | - for (final serializer in builtJsonSerializers._serializersByName.values) { |
50 | | - add(serializer); |
51 | | - } |
52 | | - } |
| 36 | + /// Serializes [object]. |
| 37 | + /// |
| 38 | + /// A [Serializer] must have been provided for every the object uses. |
| 39 | + /// |
| 40 | + /// Types that are known statically can be provided via [genericType]. This |
| 41 | + /// will reduce the amount of data needed on the wire. The exact same |
| 42 | + /// [genericType] will be needed to deserialize. |
| 43 | + /// |
| 44 | + /// Create one using [SerializersBuilder]. |
| 45 | + Object serialize(Object object, |
| 46 | + {GenericType genericType: const GenericType()}); |
| 47 | + |
| 48 | + /// Deserializes [serialized]. |
| 49 | + /// |
| 50 | + /// A [Serializer] must have been provided for every the object uses. |
| 51 | + /// |
| 52 | + /// If [serialized] was produced by calling [serialize] with [genericType], |
| 53 | + /// the exact same [genericType] must be provided to deserialize. |
| 54 | + Object deserialize(Object serialized, |
| 55 | + {GenericType genericType: const GenericType()}); |
| 56 | + |
| 57 | + /// Creates a new builder for the type represented by [genericType]. |
| 58 | + /// |
| 59 | + /// For example, if [genericType] is `BuiltList<int, String>`, returns a |
| 60 | + /// `ListBuilder<int, String>`. This helps serializers to instantiate with |
| 61 | + /// correct generic type parameters. |
| 62 | + /// |
| 63 | + /// May return null if no matching builder factory has been added. In this |
| 64 | + /// case the serializer should fall back to `Object`. |
| 65 | + Object newBuilder(GenericType genericType); |
| 66 | + |
| 67 | + SerializersBuilder toBuilder(); |
| 68 | +} |
53 | 69 |
|
54 | | - void add(BuiltJsonSerializer builtJsonSerializer) { |
55 | | - _deobfuscatedNames[_getName(builtJsonSerializer.type)] = |
56 | | - builtJsonSerializer.typeName; |
57 | | - _serializersByName[builtJsonSerializer.typeName] = builtJsonSerializer; |
58 | | - } |
| 70 | +/// Builder for [Serializers]. |
| 71 | +abstract class SerializersBuilder { |
| 72 | + factory SerializersBuilder() = BuiltJsonSerializersBuilder; |
59 | 73 |
|
60 | | - Object serialize(Object object, {String expectedType}) { |
61 | | - final rawName = _deobfuscatedNames[_getName(object.runtimeType)]; |
62 | | - if (rawName == null) throw new StateError( |
63 | | - "No serializer for '${object.runtimeType}'."); |
64 | | - |
65 | | - var genericType = _getGenericName(object.runtimeType); |
66 | | - |
67 | | - // TODO(davidmorgan): handle this generically. |
68 | | - if (genericType == 'BuiltList<int>') { |
69 | | - genericType = 'List<int>'; |
70 | | - } |
71 | | - if (genericType == 'BuiltSet<int>') { |
72 | | - genericType = 'Set<int>'; |
73 | | - } |
74 | | - |
75 | | - final genericName = |
76 | | - genericType == null ? rawName : '$rawName<$genericType>'; |
77 | | - |
78 | | - if (genericName == expectedType) { |
79 | | - return _serializersByName[rawName] |
80 | | - .serialize(this, object, expectedType: genericType); |
81 | | - } else { |
82 | | - return <String, Object>{ |
83 | | - genericName: _serializersByName[rawName] |
84 | | - .serialize(this, object, expectedType: genericType) |
85 | | - }; |
86 | | - } |
87 | | - } |
| 74 | + void add(Serializer serializer); |
88 | 75 |
|
89 | | - Object deserialize(Object object, {String expectedType}) { |
90 | | - if (object is Map) { |
91 | | - if (object.keys.length > 1) { |
92 | | - // Must be expectedType. |
93 | | - // TODO(davidmorgan): distinguish in the one field case. |
94 | | - if (expectedType == null) { |
95 | | - throw new StateError('Need an expected type here.'); |
96 | | - } |
97 | | - final typeName = _makeRaw(expectedType); |
98 | | - final genericName = _getGeneric(expectedType); |
99 | | - return _serializersByName[typeName] |
100 | | - .deserialize(this, object, expectedType: genericName); |
101 | | - } else { |
102 | | - final typeName = _makeRaw(object.keys.single); |
103 | | - final genericName = _getGeneric(object.keys.single); |
104 | | - return _serializersByName[typeName] |
105 | | - .deserialize(this, object.values.single, expectedType: genericName); |
106 | | - } |
107 | | - } else { |
108 | | - final serializer = _serializersByName[_makeRaw(expectedType)]; |
109 | | - if (serializer == null) { |
110 | | - throw new StateError('No serializer for $expectedType'); |
111 | | - } |
112 | | - return serializer.deserialize(this, object, |
113 | | - expectedType: _getGeneric(expectedType)); |
114 | | - } |
115 | | - } |
| 76 | + void addBuilderFactory(GenericType genericType, Function function); |
116 | 77 |
|
117 | | - String _getName(Type type) => _makeRaw(type.toString()); |
| 78 | + Serializers build(); |
| 79 | +} |
118 | 80 |
|
119 | | - String _makeRaw(String name) { |
120 | | - final genericsStart = name.indexOf('<'); |
121 | | - return genericsStart == -1 ? name : name.substring(0, genericsStart); |
122 | | - } |
| 81 | +/// A tree of [Type] instances. |
| 82 | +class GenericType { |
| 83 | + /// The root of the type. |
| 84 | + final Type root; |
123 | 85 |
|
124 | | - String _getGenericName(Type type) => _getGeneric(type.toString()); |
| 86 | + /// Type parameters of the type. |
| 87 | + final List<GenericType> leaves; |
125 | 88 |
|
126 | | - String _getGeneric(String name) { |
127 | | - final genericsStart = name.indexOf('<'); |
128 | | - return genericsStart == -1 |
129 | | - ? null |
130 | | - : name.substring(genericsStart + 1, name.length - 1); |
131 | | - } |
| 89 | + const GenericType([this.root = Object, this.leaves = const []]); |
| 90 | + |
| 91 | + bool get isObject => root == Object; |
| 92 | +} |
| 93 | + |
| 94 | +/// Serializes a single type. |
| 95 | +/// |
| 96 | +/// You should not usually need to implement this interface. Implementations |
| 97 | +/// are provided for collections and primitives in `built_json`. Classes using |
| 98 | +/// `built_value` and enums using `EnumClass` can have implementations |
| 99 | +/// generated using `built_json_generator`. |
| 100 | +abstract class Serializer<T> { |
| 101 | + /// Whether the serialized format for this type is structured or primitive. |
| 102 | + bool get structured; |
| 103 | + |
| 104 | + /// The [Type]s that can be serialized. |
| 105 | + /// |
| 106 | + /// They must all be equal to T or subclasses of T. |
| 107 | + Iterable<Type> get types; |
| 108 | + |
| 109 | + /// The wire name of the serializable type. For most classes, the class name. |
| 110 | + /// For primitives and collections a lower-case name is defined as part of |
| 111 | + /// the `built_json` wire format. |
| 112 | + String get wireName; |
| 113 | + |
| 114 | + /// Serializes [object]. |
| 115 | + /// |
| 116 | + /// Use [serializers] as needed for nested serialization. Information about |
| 117 | + /// the type being serialized is provided in [genericType]. |
| 118 | + Object serialize(Serializers serializers, T object, |
| 119 | + {GenericType genericType: const GenericType()}); |
| 120 | + |
| 121 | + /// Deserializes [serialized]. |
| 122 | + /// |
| 123 | + /// Use [serializers] as needed for nested deserialization. Information about |
| 124 | + /// the type being deserialized is provided in [genericType]. |
| 125 | + T deserialize(Serializers serializers, Object serialized, |
| 126 | + {GenericType genericType: const GenericType()}); |
132 | 127 | } |
0 commit comments