Skip to content
This repository was archived by the owner on May 25, 2022. It is now read-only.

Commit 2eee3cb

Browse files
committed
Merge pull request #5 from google/explit-static-dynamic-serialization
Rewrite to fully use static type information
2 parents 0ab60a8 + e8ee085 commit 2eee3cb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+2100
-689
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## 0.0.2
4+
5+
- Rewrite to fully use static type information.
6+
37
## 0.0.1
48

59
- Generator, tests and example.

built_json/lib/built_json.dart

Lines changed: 100 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -5,128 +5,123 @@
55
library built_json;
66

77
import 'src/bool_serializer.dart';
8+
import 'src/built_json_serializers.dart';
89
import 'src/built_list_serializer.dart';
910
import 'src/built_map_serializer.dart';
1011
import 'src/built_set_serializer.dart';
1112
import 'src/double_serializer.dart';
1213
import 'src/int_serializer.dart';
1314
import 'src/string_serializer.dart';
1415

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;
2717

28-
/// Serializes all transitive dependencies of a class.
18+
/// Serializes all known classes.
2919
///
3020
/// 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();
4634
}
4735

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+
}
5369

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;
5973

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);
8875

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);
11677

117-
String _getName(Type type) => _makeRaw(type.toString());
78+
Serializers build();
79+
}
11880

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;
12385

124-
String _getGenericName(Type type) => _getGeneric(type.toString());
86+
/// Type parameters of the type.
87+
final List<GenericType> leaves;
12588

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()});
132127
}

built_json/lib/src/bool_serializer.dart

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,23 @@
22
// All rights reserved. Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5+
import 'package:built_collection/built_collection.dart';
56
import 'package:built_json/built_json.dart';
67

7-
class BoolSerializer implements BuiltJsonSerializer<bool> {
8-
final Type type = bool;
9-
final String typeName = 'bool';
8+
class BoolSerializer implements Serializer<bool> {
9+
final bool structured = false;
10+
final Iterable<Type> types = new BuiltList<Type>([bool]);
11+
final String wireName = 'bool';
1012

11-
Object serialize(BuiltJsonSerializers builtJsonSerializers, bool object,
12-
{String expectedType}) {
13+
@override
14+
Object serialize(Serializers serializers, bool object,
15+
{GenericType genericType: const GenericType()}) {
1316
return object;
1417
}
1518

16-
bool deserialize(BuiltJsonSerializers builtJsonSerializers, Object object,
17-
{String expectedType}) {
19+
@override
20+
bool deserialize(Serializers serializers, Object object,
21+
{GenericType genericType: const GenericType()}) {
1822
return object as bool;
1923
}
2024
}

0 commit comments

Comments
 (0)