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

Commit

Permalink
Merge pull request #20 from davidmorgan/review-comments
Browse files Browse the repository at this point in the history
Add PrimitiveSerializer and StructuredSerializer interfaces.
  • Loading branch information
davidmorgan committed Mar 18, 2016
2 parents 5a27597 + e249642 commit c314cf1
Show file tree
Hide file tree
Showing 21 changed files with 200 additions and 165 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## 0.0.5

- Add PrimitiveSerializer and StructuredSerializer interfaces.

## 0.0.4

- Update built_value dependency to 0.0.6.
Expand Down
46 changes: 40 additions & 6 deletions built_json/lib/built_json.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export 'package:built_collection/built_collection.dart' show BuiltList;

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

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

/// Deserializes [serialized].
///
/// A [Serializer] must have been provided for every the object uses.
/// A [Serializer] must have been provided for every type the object uses.
///
/// If [serialized] was produced by calling [serialize] with [specifiedType],
/// the exact same [specifiedType] must be provided to deserialize.
Expand Down Expand Up @@ -115,10 +115,10 @@ class FullType {
/// are provided for collections and primitives in `built_json`. Classes using
/// `built_value` and enums using `EnumClass` can have implementations
/// generated using `built_json_generator`.
///
/// Implementations must extend either [PrimitiveSerializer] or
/// [StructuredSerializer].
abstract class Serializer<T> {
/// Whether the serialized format for this type is structured or primitive.
bool get structured;

/// The [Type]s that can be serialized.
///
/// They must all be equal to T or a subclass of T. Subclasses are used when
Expand All @@ -130,20 +130,54 @@ abstract class Serializer<T> {
/// For primitives and collections a lower-case name is defined as part of
/// the `built_json` wire format.
String get wireName;
}

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

/// Deserializes [serialized].
///
/// [serialized] is a boolean, an integer, a double or a String.
///
/// Use [serializers] as needed for nested deserialization. Information about
/// the type being deserialized is provided in [specifiedType].
T deserialize(Serializers serializers, Object serialized,
{FullType specifiedType: FullType.unspecified});
}

/// A [Serializer] that serializes to and from an [Iterable] of primitive JSON
/// values.
abstract class StructuredSerializer<T> implements Serializer<T> {
/// Serializes [object].
///
/// Use [serializers] as needed for nested serialization. Information about
/// the type being serialized is provided in [specifiedType].
///
/// Returns an [Iterable] of values that can be represented as structured
/// JSON: booleans, integers, doubles, Strings and [Iterable]s.
///
/// TODO(davidmorgan): document the wire format.
Iterable serialize(Serializers serializers, T object,
{FullType specifiedType: FullType.unspecified});

/// Deserializes [serialized].
///
/// [serialized] is an [Iterable] that may contain booleans, integers,
/// doubles, Strings and/or [Iterable]s.
///
/// Use [serializers] as needed for nested deserialization. Information about
/// the type being deserialized is provided in [specifiedType].
T deserialize(Serializers serializers, Iterable serialized,
{FullType specifiedType: FullType.unspecified});
}
2 changes: 1 addition & 1 deletion built_json/lib/src/bool_serializer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import 'package:built_collection/built_collection.dart';
import 'package:built_json/built_json.dart';

class BoolSerializer implements Serializer<bool> {
class BoolSerializer implements PrimitiveSerializer<bool> {
final bool structured = false;
final Iterable<Type> types = new BuiltList<Type>([bool]);
final String wireName = 'bool';
Expand Down
92 changes: 67 additions & 25 deletions built_json/lib/src/built_json_serializers.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Copyright (c) 2015, Google Inc. Please see the AUTHORS file for details.

// All rights reserved. Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

Expand All @@ -8,8 +9,17 @@ import 'package:built_json/built_json.dart';
/// Default implementation of [Serializers].
class BuiltJsonSerializers implements Serializers {
final BuiltMap<Type, Serializer> _typeToSerializer;

// Implementation note: wire name is what gets sent in the JSON, type name is
// the runtime type name. Type name is complicated for two reasons:
//
// 1. Built Value classes have two types, the abstract class and the
// generated implementation.
//
// 2. When compiled to javascript the runtime type names are obfuscated.
final BuiltMap<String, Serializer> _wireNameToSerializer;
final BuiltMap<String, Serializer> _typeNameToSerializer;

final BuiltMap<FullType, Function> _builderFactories;

BuiltJsonSerializers._(this._typeToSerializer, this._wireNameToSerializer,
Expand All @@ -20,23 +30,36 @@ class BuiltJsonSerializers implements Serializers {
{FullType specifiedType: FullType.unspecified}) {
if (specifiedType.isUnspecified) {
final serializer = _getSerializerByType(object.runtimeType);
if (serializer == null) throw new StateError(
"No serializer for '${object.runtimeType}'.");
final serialized = serializer.serialize(this, object);

if (serializer.structured) {
if (serializer == null) {
throw new StateError("No serializer for '${object.runtimeType}'.");
}
if (serializer is StructuredSerializer) {
final result = <Object>[serializer.wireName];
return result..addAll(serialized as Iterable);
return result..addAll(serializer.serialize(this, object));
} else if (serializer is PrimitiveSerializer) {
return <Object>[
serializer.wireName,
serializer.serialize(this, object)
];
} else {
return <Object>[serializer.wireName, serialized];
throw new StateError(
'serializer must be StructuredSerializer or PrimitiveSerializer');
}
} else {
final serializer = _getSerializerByType(specifiedType.root);
if (serializer == null) throw new StateError(
"No serializer for '${specifiedType.root}'.");
final result =
serializer.serialize(this, object, specifiedType: specifiedType);
return serializer.structured ? (result as Iterable).toList() : result;
if (serializer == null) {
throw new StateError("No serializer for '${specifiedType.root}'.");
}
if (serializer is StructuredSerializer) {
return serializer
.serialize(this, object, specifiedType: specifiedType)
.toList();
} else if (serializer is PrimitiveSerializer) {
return serializer.serialize(this, object, specifiedType: specifiedType);
} else {
throw new StateError(
'serializer must be StructuredSerializer or PrimitiveSerializer');
}
}
}

Expand All @@ -50,15 +73,29 @@ class BuiltJsonSerializers implements Serializers {
if (serializer == null) {
throw new StateError("No serializer for '${wireName}'.");
}
final json = serializer.structured
? (object as List).sublist(1)
: (object as List)[1];
return serializer.deserialize(this, json);

if (serializer is StructuredSerializer) {
return serializer.deserialize(this, (object as List).sublist(1));
} else if (serializer is PrimitiveSerializer) {
return serializer.deserialize(this, (object as List)[1]);
} else {
throw new StateError(
'serializer must be StructuredSerializer or PrimitiveSerializer');
}
} else {
final serializer = _getSerializerByType(specifiedType.root);
if (serializer == null) throw new StateError(
"No serializer for '${specifiedType.root}'.");
return serializer.deserialize(this, object, specifiedType: specifiedType);
if (serializer == null) {
throw new StateError("No serializer for '${specifiedType.root}'.");
}

if (serializer is StructuredSerializer) {
return serializer.deserialize(this, object as Iterable, specifiedType: specifiedType);
} else if (serializer is PrimitiveSerializer) {
return serializer.deserialize(this, object, specifiedType: specifiedType);
} else {
throw new StateError(
'serializer must be StructuredSerializer or PrimitiveSerializer');
}
}
}

Expand Down Expand Up @@ -90,24 +127,29 @@ class BuiltJsonSerializers implements Serializers {
/// Default implementation of [SerializersBuilder].
class BuiltJsonSerializersBuilder implements SerializersBuilder {
MapBuilder<Type, Serializer> _typeToSerializer =
new MapBuilder<Type, Serializer>();
new MapBuilder<Type, Serializer>();
MapBuilder<String, Serializer> _wireNameToSerializer =
new MapBuilder<String, Serializer>();
new MapBuilder<String, Serializer>();
MapBuilder<String, Serializer> _typeNameToSerializer =
new MapBuilder<String, Serializer>();
new MapBuilder<String, Serializer>();

MapBuilder<FullType, Function> _builderFactories =
new MapBuilder<FullType, Function>();
new MapBuilder<FullType, Function>();

BuiltJsonSerializersBuilder();

BuiltJsonSerializersBuilder._(
this._typeToSerializer,
BuiltJsonSerializersBuilder._(this._typeToSerializer,
this._wireNameToSerializer,
this._typeNameToSerializer,
this._builderFactories);

void add(Serializer serializer) {
if (serializer is! StructuredSerializer &&
serializer is! PrimitiveSerializer) {
throw new ArgumentError(
'serializer must be StructuredSerializer or PrimitiveSerializer');
}

_wireNameToSerializer[serializer.wireName] = serializer;
for (final type in serializer.types) {
_typeToSerializer[type] = serializer;
Expand Down
10 changes: 5 additions & 5 deletions built_json/lib/src/built_list_serializer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
import 'package:built_collection/built_collection.dart';
import 'package:built_json/built_json.dart';

class BuiltListSerializer implements Serializer<BuiltList> {
class BuiltListSerializer implements StructuredSerializer<BuiltList> {
final bool structured = true;
final Iterable<Type> types = new BuiltList<Type>([BuiltList]);
final String wireName = 'list';

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

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

final result = isUnderspecified
ListBuilder result = isUnderspecified
? new ListBuilder<Object>()
: serializers.newBuilder(specifiedType) as ListBuilder;
if (result == null) {
throw new StateError(
'No builder for $specifiedType, cannot deserialize.');
}
result.addAll((serialized as Iterable).map((item) =>
result.addAll(serialized.map((item) =>
serializers.deserialize(item, specifiedType: elementType)));
return result.build();
}
Expand Down
20 changes: 10 additions & 10 deletions built_json/lib/src/built_map_serializer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
import 'package:built_collection/built_collection.dart';
import 'package:built_json/built_json.dart';

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

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

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

final result = isUnderspecified
MapBuilder result = isUnderspecified
? new MapBuilder<Object, Object>()
: serializers.newBuilder(specifiedType) as MapBuilder;
if (result == null) {
throw new StateError(
'No builder for $specifiedType, cannot deserialize.');
}
final list = serialized as List<Object>;

if (list.length & 1 == 1) {
if (serialized.length % 2 == 1) {
throw new ArgumentError('odd length');
}

for (int i = 0; i != list.length; i += 2) {
final key = serializers.deserialize(list[i], specifiedType: keyType);
final value =
serializers.deserialize(list[i + 1], specifiedType: valueType);
for (int i = 0; i != serialized.length; i += 2) {
final key = serializers.deserialize(serialized.elementAt(i),
specifiedType: keyType);
final value = serializers.deserialize(serialized.elementAt(i + 1),
specifiedType: valueType);
result[key] = value;
}

Expand Down
Loading

0 comments on commit c314cf1

Please sign in to comment.