|
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