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

Commit c314cf1

Browse files
committed
Merge pull request #20 from davidmorgan/review-comments
Add PrimitiveSerializer and StructuredSerializer interfaces.
2 parents 5a27597 + e249642 commit c314cf1

21 files changed

+200
-165
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## 0.0.5
4+
5+
- Add PrimitiveSerializer and StructuredSerializer interfaces.
6+
37
## 0.0.4
48

59
- Update built_value dependency to 0.0.6.

built_json/lib/built_json.dart

+40-6
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export 'package:built_collection/built_collection.dart' show BuiltList;
1717

1818
/// Serializes all known classes.
1919
///
20-
/// See <https://github.com/google/built_json.dart/tree/master/example>
20+
/// See: https://github.com/google/built_json.dart/tree/master/example
2121
abstract class Serializers {
2222
/// Default [Serializers] that can serialize primitives and collections.
2323
///
@@ -35,7 +35,7 @@ abstract class Serializers {
3535

3636
/// Serializes [object].
3737
///
38-
/// A [Serializer] must have been provided for every the object uses.
38+
/// A [Serializer] must have been provided for every type the object uses.
3939
///
4040
/// Types that are known statically can be provided via [specifiedType]. This
4141
/// will reduce the amount of data needed on the wire. The exact same
@@ -49,7 +49,7 @@ abstract class Serializers {
4949

5050
/// Deserializes [serialized].
5151
///
52-
/// A [Serializer] must have been provided for every the object uses.
52+
/// A [Serializer] must have been provided for every type the object uses.
5353
///
5454
/// If [serialized] was produced by calling [serialize] with [specifiedType],
5555
/// the exact same [specifiedType] must be provided to deserialize.
@@ -115,10 +115,10 @@ class FullType {
115115
/// are provided for collections and primitives in `built_json`. Classes using
116116
/// `built_value` and enums using `EnumClass` can have implementations
117117
/// generated using `built_json_generator`.
118+
///
119+
/// Implementations must extend either [PrimitiveSerializer] or
120+
/// [StructuredSerializer].
118121
abstract class Serializer<T> {
119-
/// Whether the serialized format for this type is structured or primitive.
120-
bool get structured;
121-
122122
/// The [Type]s that can be serialized.
123123
///
124124
/// They must all be equal to T or a subclass of T. Subclasses are used when
@@ -130,20 +130,54 @@ abstract class Serializer<T> {
130130
/// For primitives and collections a lower-case name is defined as part of
131131
/// the `built_json` wire format.
132132
String get wireName;
133+
}
133134

135+
/// A [Serializer] that serializes to and from primitive JSON values.
136+
abstract class PrimitiveSerializer<T> implements Serializer<T> {
134137
/// Serializes [object].
135138
///
136139
/// Use [serializers] as needed for nested serialization. Information about
137140
/// the type being serialized is provided in [specifiedType].
138141
///
142+
/// Returns a value that can be represented as a JSON primitive: a boolean,
143+
/// an integer, a double, or a String.
144+
///
139145
/// TODO(davidmorgan): document the wire format.
140146
Object serialize(Serializers serializers, T object,
141147
{FullType specifiedType: FullType.unspecified});
142148

143149
/// Deserializes [serialized].
144150
///
151+
/// [serialized] is a boolean, an integer, a double or a String.
152+
///
145153
/// Use [serializers] as needed for nested deserialization. Information about
146154
/// the type being deserialized is provided in [specifiedType].
147155
T deserialize(Serializers serializers, Object serialized,
148156
{FullType specifiedType: FullType.unspecified});
149157
}
158+
159+
/// A [Serializer] that serializes to and from an [Iterable] of primitive JSON
160+
/// values.
161+
abstract class StructuredSerializer<T> implements Serializer<T> {
162+
/// Serializes [object].
163+
///
164+
/// Use [serializers] as needed for nested serialization. Information about
165+
/// the type being serialized is provided in [specifiedType].
166+
///
167+
/// Returns an [Iterable] of values that can be represented as structured
168+
/// JSON: booleans, integers, doubles, Strings and [Iterable]s.
169+
///
170+
/// TODO(davidmorgan): document the wire format.
171+
Iterable serialize(Serializers serializers, T object,
172+
{FullType specifiedType: FullType.unspecified});
173+
174+
/// Deserializes [serialized].
175+
///
176+
/// [serialized] is an [Iterable] that may contain booleans, integers,
177+
/// doubles, Strings and/or [Iterable]s.
178+
///
179+
/// Use [serializers] as needed for nested deserialization. Information about
180+
/// the type being deserialized is provided in [specifiedType].
181+
T deserialize(Serializers serializers, Iterable serialized,
182+
{FullType specifiedType: FullType.unspecified});
183+
}

built_json/lib/src/bool_serializer.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import 'package:built_collection/built_collection.dart';
66
import 'package:built_json/built_json.dart';
77

8-
class BoolSerializer implements Serializer<bool> {
8+
class BoolSerializer implements PrimitiveSerializer<bool> {
99
final bool structured = false;
1010
final Iterable<Type> types = new BuiltList<Type>([bool]);
1111
final String wireName = 'bool';

built_json/lib/src/built_json_serializers.dart

+67-25
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// Copyright (c) 2015, Google Inc. Please see the AUTHORS file for details.
2+
23
// All rights reserved. Use of this source code is governed by a BSD-style
34
// license that can be found in the LICENSE file.
45

@@ -8,8 +9,17 @@ import 'package:built_json/built_json.dart';
89
/// Default implementation of [Serializers].
910
class BuiltJsonSerializers implements Serializers {
1011
final BuiltMap<Type, Serializer> _typeToSerializer;
12+
13+
// Implementation note: wire name is what gets sent in the JSON, type name is
14+
// the runtime type name. Type name is complicated for two reasons:
15+
//
16+
// 1. Built Value classes have two types, the abstract class and the
17+
// generated implementation.
18+
//
19+
// 2. When compiled to javascript the runtime type names are obfuscated.
1120
final BuiltMap<String, Serializer> _wireNameToSerializer;
1221
final BuiltMap<String, Serializer> _typeNameToSerializer;
22+
1323
final BuiltMap<FullType, Function> _builderFactories;
1424

1525
BuiltJsonSerializers._(this._typeToSerializer, this._wireNameToSerializer,
@@ -20,23 +30,36 @@ class BuiltJsonSerializers implements Serializers {
2030
{FullType specifiedType: FullType.unspecified}) {
2131
if (specifiedType.isUnspecified) {
2232
final serializer = _getSerializerByType(object.runtimeType);
23-
if (serializer == null) throw new StateError(
24-
"No serializer for '${object.runtimeType}'.");
25-
final serialized = serializer.serialize(this, object);
26-
27-
if (serializer.structured) {
33+
if (serializer == null) {
34+
throw new StateError("No serializer for '${object.runtimeType}'.");
35+
}
36+
if (serializer is StructuredSerializer) {
2837
final result = <Object>[serializer.wireName];
29-
return result..addAll(serialized as Iterable);
38+
return result..addAll(serializer.serialize(this, object));
39+
} else if (serializer is PrimitiveSerializer) {
40+
return <Object>[
41+
serializer.wireName,
42+
serializer.serialize(this, object)
43+
];
3044
} else {
31-
return <Object>[serializer.wireName, serialized];
45+
throw new StateError(
46+
'serializer must be StructuredSerializer or PrimitiveSerializer');
3247
}
3348
} else {
3449
final serializer = _getSerializerByType(specifiedType.root);
35-
if (serializer == null) throw new StateError(
36-
"No serializer for '${specifiedType.root}'.");
37-
final result =
38-
serializer.serialize(this, object, specifiedType: specifiedType);
39-
return serializer.structured ? (result as Iterable).toList() : result;
50+
if (serializer == null) {
51+
throw new StateError("No serializer for '${specifiedType.root}'.");
52+
}
53+
if (serializer is StructuredSerializer) {
54+
return serializer
55+
.serialize(this, object, specifiedType: specifiedType)
56+
.toList();
57+
} else if (serializer is PrimitiveSerializer) {
58+
return serializer.serialize(this, object, specifiedType: specifiedType);
59+
} else {
60+
throw new StateError(
61+
'serializer must be StructuredSerializer or PrimitiveSerializer');
62+
}
4063
}
4164
}
4265

@@ -50,15 +73,29 @@ class BuiltJsonSerializers implements Serializers {
5073
if (serializer == null) {
5174
throw new StateError("No serializer for '${wireName}'.");
5275
}
53-
final json = serializer.structured
54-
? (object as List).sublist(1)
55-
: (object as List)[1];
56-
return serializer.deserialize(this, json);
76+
77+
if (serializer is StructuredSerializer) {
78+
return serializer.deserialize(this, (object as List).sublist(1));
79+
} else if (serializer is PrimitiveSerializer) {
80+
return serializer.deserialize(this, (object as List)[1]);
81+
} else {
82+
throw new StateError(
83+
'serializer must be StructuredSerializer or PrimitiveSerializer');
84+
}
5785
} else {
5886
final serializer = _getSerializerByType(specifiedType.root);
59-
if (serializer == null) throw new StateError(
60-
"No serializer for '${specifiedType.root}'.");
61-
return serializer.deserialize(this, object, specifiedType: specifiedType);
87+
if (serializer == null) {
88+
throw new StateError("No serializer for '${specifiedType.root}'.");
89+
}
90+
91+
if (serializer is StructuredSerializer) {
92+
return serializer.deserialize(this, object as Iterable, specifiedType: specifiedType);
93+
} else if (serializer is PrimitiveSerializer) {
94+
return serializer.deserialize(this, object, specifiedType: specifiedType);
95+
} else {
96+
throw new StateError(
97+
'serializer must be StructuredSerializer or PrimitiveSerializer');
98+
}
6299
}
63100
}
64101

@@ -90,24 +127,29 @@ class BuiltJsonSerializers implements Serializers {
90127
/// Default implementation of [SerializersBuilder].
91128
class BuiltJsonSerializersBuilder implements SerializersBuilder {
92129
MapBuilder<Type, Serializer> _typeToSerializer =
93-
new MapBuilder<Type, Serializer>();
130+
new MapBuilder<Type, Serializer>();
94131
MapBuilder<String, Serializer> _wireNameToSerializer =
95-
new MapBuilder<String, Serializer>();
132+
new MapBuilder<String, Serializer>();
96133
MapBuilder<String, Serializer> _typeNameToSerializer =
97-
new MapBuilder<String, Serializer>();
134+
new MapBuilder<String, Serializer>();
98135

99136
MapBuilder<FullType, Function> _builderFactories =
100-
new MapBuilder<FullType, Function>();
137+
new MapBuilder<FullType, Function>();
101138

102139
BuiltJsonSerializersBuilder();
103140

104-
BuiltJsonSerializersBuilder._(
105-
this._typeToSerializer,
141+
BuiltJsonSerializersBuilder._(this._typeToSerializer,
106142
this._wireNameToSerializer,
107143
this._typeNameToSerializer,
108144
this._builderFactories);
109145

110146
void add(Serializer serializer) {
147+
if (serializer is! StructuredSerializer &&
148+
serializer is! PrimitiveSerializer) {
149+
throw new ArgumentError(
150+
'serializer must be StructuredSerializer or PrimitiveSerializer');
151+
}
152+
111153
_wireNameToSerializer[serializer.wireName] = serializer;
112154
for (final type in serializer.types) {
113155
_typeToSerializer[type] = serializer;

built_json/lib/src/built_list_serializer.dart

+5-5
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@
55
import 'package:built_collection/built_collection.dart';
66
import 'package:built_json/built_json.dart';
77

8-
class BuiltListSerializer implements Serializer<BuiltList> {
8+
class BuiltListSerializer implements StructuredSerializer<BuiltList> {
99
final bool structured = true;
1010
final Iterable<Type> types = new BuiltList<Type>([BuiltList]);
1111
final String wireName = 'list';
1212

1313
@override
14-
Object serialize(Serializers serializers, BuiltList builtList,
14+
Iterable serialize(Serializers serializers, BuiltList builtList,
1515
{FullType specifiedType: FullType.unspecified}) {
1616
final isUnderspecified =
1717
specifiedType.isUnspecified || specifiedType.parameters.isEmpty;
@@ -30,7 +30,7 @@ class BuiltListSerializer implements Serializer<BuiltList> {
3030
}
3131

3232
@override
33-
BuiltList deserialize(Serializers serializers, Object serialized,
33+
BuiltList deserialize(Serializers serializers, Iterable serialized,
3434
{FullType specifiedType: FullType.unspecified}) {
3535
final isUnderspecified =
3636
specifiedType.isUnspecified || specifiedType.parameters.isEmpty;
@@ -39,14 +39,14 @@ class BuiltListSerializer implements Serializer<BuiltList> {
3939
? FullType.unspecified
4040
: specifiedType.parameters[0];
4141

42-
final result = isUnderspecified
42+
ListBuilder result = isUnderspecified
4343
? new ListBuilder<Object>()
4444
: serializers.newBuilder(specifiedType) as ListBuilder;
4545
if (result == null) {
4646
throw new StateError(
4747
'No builder for $specifiedType, cannot deserialize.');
4848
}
49-
result.addAll((serialized as Iterable).map((item) =>
49+
result.addAll(serialized.map((item) =>
5050
serializers.deserialize(item, specifiedType: elementType)));
5151
return result.build();
5252
}

built_json/lib/src/built_map_serializer.dart

+10-10
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@
55
import 'package:built_collection/built_collection.dart';
66
import 'package:built_json/built_json.dart';
77

8-
class BuiltMapSerializer implements Serializer<BuiltMap> {
8+
class BuiltMapSerializer implements StructuredSerializer<BuiltMap> {
99
final bool structured = true;
1010
final Iterable<Type> types = new BuiltList<Type>([BuiltMap]);
1111
final String wireName = 'map';
1212

1313
@override
14-
Object serialize(Serializers serializers, BuiltMap builtMap,
14+
Iterable serialize(Serializers serializers, BuiltMap builtMap,
1515
{FullType specifiedType: FullType.unspecified}) {
1616
final isUnderspecified =
1717
specifiedType.isUnspecified || specifiedType.parameters.isEmpty;
@@ -37,7 +37,7 @@ class BuiltMapSerializer implements Serializer<BuiltMap> {
3737
}
3838

3939
@override
40-
BuiltMap deserialize(Serializers serializers, Object serialized,
40+
BuiltMap deserialize(Serializers serializers, Iterable serialized,
4141
{FullType specifiedType: FullType.unspecified}) {
4242
final isUnderspecified =
4343
specifiedType.isUnspecified || specifiedType.parameters.isEmpty;
@@ -49,23 +49,23 @@ class BuiltMapSerializer implements Serializer<BuiltMap> {
4949
? FullType.unspecified
5050
: specifiedType.parameters[1];
5151

52-
final result = isUnderspecified
52+
MapBuilder result = isUnderspecified
5353
? new MapBuilder<Object, Object>()
5454
: serializers.newBuilder(specifiedType) as MapBuilder;
5555
if (result == null) {
5656
throw new StateError(
5757
'No builder for $specifiedType, cannot deserialize.');
5858
}
59-
final list = serialized as List<Object>;
6059

61-
if (list.length & 1 == 1) {
60+
if (serialized.length % 2 == 1) {
6261
throw new ArgumentError('odd length');
6362
}
6463

65-
for (int i = 0; i != list.length; i += 2) {
66-
final key = serializers.deserialize(list[i], specifiedType: keyType);
67-
final value =
68-
serializers.deserialize(list[i + 1], specifiedType: valueType);
64+
for (int i = 0; i != serialized.length; i += 2) {
65+
final key = serializers.deserialize(serialized.elementAt(i),
66+
specifiedType: keyType);
67+
final value = serializers.deserialize(serialized.elementAt(i + 1),
68+
specifiedType: valueType);
6969
result[key] = value;
7070
}
7171

0 commit comments

Comments
 (0)