Skip to content

Use .map instead of new Map.fromIterables in a couple of places #161

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions json_serializable/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
## 0.5.4

* Use `Map.map` for more map conversions. Simplifies generated code and fixes
a subtle issue when the `Map` key type is `dynamic` or `Object`.

* Added `any_map` to configuration. Allows `fromJson` code to
support dynamic `Map` instances that are not explicitly
`Map<String, dynaimc>`.
Expand Down
50 changes: 24 additions & 26 deletions json_serializable/lib/src/type_helpers/map_helper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,10 @@ class MapHelper extends TypeHelper {
return '$method<$keyType, $valueType>($expression, ($_closureArg) => $subFieldValue)';
}

var result = 'new Map<String, dynamic>.fromIterables('
'$expression.keys,'
'$expression.values.map(($_closureArg) => $subFieldValue))';
final optionalQuestion = context.nullable ? '?' : '';

return commonNullPrefix(context.nullable, expression, result);
return '$expression$optionalQuestion'
'.map((k, $_closureArg) => new MapEntry(k, $subFieldValue))';
}

@override
Expand All @@ -58,22 +57,19 @@ class MapHelper extends TypeHelper {
return null;
}

// Just pass through if
// key: dynamic, Object, String
// value: dynamic, Object
var typeArgs = typeArgumentsOf(targetType, coreMapTypeChecker);
assert(typeArgs.length == 2);
var keyArg = typeArgs.first;
var valueArg = typeArgs.last;

_checkSafeKeyType(expression, keyArg);

var valueArgIsAny = valueArg.isDynamic || valueArg.isObject;
final valueArgIsAny = _isObjectOrDynamic(valueArg);
var isAnyMap = context is TypeHelperContext && context.anyMap;

if (valueArgIsAny) {
if (isAnyMap) {
if (keyArg.isObject || keyArg.isDynamic) {
if (_isObjectOrDynamic(keyArg)) {
return '$expression as Map';
}
} else {
Expand All @@ -93,28 +89,30 @@ class MapHelper extends TypeHelper {
// In this case, we're going to create a new Map with matching reified
// types.

var itemSubVal = context.deserialize(valueArg, _closureArg);
final itemSubVal = context.deserialize(valueArg, _closureArg);

var keyIterable = isAnyMap
? '($expression as Map).keys.cast<String>()'
: '($expression as Map<String, dynamic>).keys';
final optionalQuestion = context.nullable ? '?' : '';

var result = 'new Map<String, $valueArg>.fromIterables($keyIterable,'
'($expression as Map).values.map(($_closureArg) => $itemSubVal))';
final mapCast = isAnyMap ? 'as Map' : 'as Map<String, dynamic>';

return commonNullPrefix(context.nullable, expression, result);
final keyUsage =
(isAnyMap && !_isObjectOrDynamic(keyArg)) ? 'k as String' : 'k';

return '($expression $mapCast)$optionalQuestion'
'.map((k, $_closureArg) => new MapEntry($keyUsage, $itemSubVal))';
}
}

void _checkSafeKeyType(String expression, DartType keyArg) {
// We're not going to handle converting key types at the moment
// So the only safe types for key are dynamic/Object/String
var safeKey = keyArg.isDynamic ||
keyArg.isObject ||
coreStringTypeChecker.isExactlyType(keyArg);
bool _isObjectOrDynamic(DartType type) => type.isObject || type.isDynamic;

if (!safeKey) {
throw new UnsupportedTypeError(keyArg, expression,
'The type of the Map key must be `String`, `Object` or `dynamic`.');
}
void _checkSafeKeyType(String expression, DartType keyArg) {
// We're not going to handle converting key types at the moment
// So the only safe types for key are dynamic/Object/String
var safeKey =
_isObjectOrDynamic(keyArg) || coreStringTypeChecker.isExactlyType(keyArg);

if (!safeKey) {
throw new UnsupportedTypeError(keyArg, expression,
'The type of the Map key must be `String`, `Object` or `dynamic`.');
}
}
14 changes: 7 additions & 7 deletions json_serializable/test/kitchen_sink_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ typedef KitchenSink KitchenSinkCtor(

void _nonNullableTests(KitchenSinkCtor ctor, KitchenSink fromJson(Map json)) {
test('with null values fails serialization', () {
expect(() => (ctor()..stringDateTimeMap = null).toJson(),
expect(() => (ctor()..objectDateTimeMap = null).toJson(),
throwsNoSuchMethodError);
});

Expand Down Expand Up @@ -92,7 +92,7 @@ void _nullableTests(KitchenSinkCtor ctor, KitchenSink fromJson(Map json)) {
var now = new DateTime.now();
var item = ctor(dateTimeIterable: <DateTime>[now])
..dateTimeList = <DateTime>[now, null]
..stringDateTimeMap = <String, DateTime>{'value': now, 'null': null};
..objectDateTimeMap = <Object, DateTime>{'value': now, 'null': null};

roundTripItem(item);
});
Expand Down Expand Up @@ -136,7 +136,7 @@ void _sharedTests(KitchenSinkCtor ctor, KitchenSink fromJson(Map json)) {
var now = new DateTime.now();
var item = ctor(dateTimeIterable: <DateTime>[now])
..dateTimeList = <DateTime>[now, now]
..stringDateTimeMap = <String, DateTime>{'value': now};
..objectDateTimeMap = <Object, DateTime>{'value': now};

roundTripSink(item);
});
Expand Down Expand Up @@ -216,8 +216,8 @@ final _validValues = const {
'dateTimeList': const [],
'map': const <String, dynamic>{},
'stringStringMap': const {},
'stringIntMap': const {},
'stringDateTimeMap': const <String, dynamic>{},
'dynamicIntMap': const {},
'objectDateTimeMap': const <String, dynamic>{},
'crazyComplex': const [],
toJsonMapVarName: const {},
toJsonMapHelperName: null,
Expand All @@ -240,8 +240,8 @@ final _invalidValues = const {
'dateTimeList': const [true],
'map': true,
'stringStringMap': const {'key': 42},
'stringIntMap': const {'key': 'value'},
'stringDateTimeMap': const {'key': 42},
'dynamicIntMap': const {'key': 'value'},
'objectDateTimeMap': const {'key': 42},
'crazyComplex': const [true],
toJsonMapVarName: const {'key': 42},
toJsonMapHelperName: 42,
Expand Down
25 changes: 8 additions & 17 deletions json_serializable/test/test_files/json_test_example.g.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,10 @@ Person _$PersonFromJson(Map<String, dynamic> json) => new Person(
..order = json['order'] == null
? null
: new Order.fromJson(json['order'] as Map<String, dynamic>)
..houseMap = json['houseMap'] == null
? null
: new Map<String, House>.fromIterables(
(json['houseMap'] as Map<String, dynamic>).keys,
(json['houseMap'] as Map).values.map((e) => e == null
..houseMap = (json['houseMap'] as Map<String, dynamic>)?.map((k, e) =>
new MapEntry(
k,
e == null
? null
: House.values.singleWhere((x) => x.toString() == 'House.$e')));

Expand All @@ -47,12 +46,8 @@ abstract class _$PersonSerializerMixin {
'dateOfBirth': dateOfBirth?.toIso8601String(),
r'$house': house == null ? null : house.toString().split('.')[1],
'order': order,
'houseMap': houseMap == null
? null
: new Map<String, dynamic>.fromIterables(
houseMap.keys,
houseMap.values
.map((e) => e == null ? null : e.toString().split('.')[1]))
'houseMap': houseMap?.map((k, e) =>
new MapEntry(k, e == null ? null : e.toString().split('.')[1]))
};
}

Expand All @@ -66,12 +61,8 @@ Order _$OrderFromJson(Map<String, dynamic> json) => new Order(
..platform = json['platform'] == null
? null
: new Platform.fromJson(json['platform'] as String)
..altPlatforms = json['altPlatforms'] == null
? null
: new Map<String, Platform>.fromIterables(
(json['altPlatforms'] as Map<String, dynamic>).keys,
(json['altPlatforms'] as Map).values.map(
(e) => e == null ? null : new Platform.fromJson(e as String)));
..altPlatforms = (json['altPlatforms'] as Map<String, dynamic>)?.map((k, e) =>
new MapEntry(k, e == null ? null : new Platform.fromJson(e as String)));

abstract class _$OrderSerializerMixin {
int get count;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,9 @@ Person _$PersonFromJson(Map<String, dynamic> json) => new Person(
middleName: json['middleName'] as String,
dateOfBirth: DateTime.parse(json['dateOfBirth'] as String))
..order = new Order.fromJson(json['order'] as Map<String, dynamic>)
..houseMap = new Map<String, House>.fromIterables(
(json['houseMap'] as Map<String, dynamic>).keys,
(json['houseMap'] as Map).values.map(
(e) => House.values.singleWhere((x) => x.toString() == 'House.$e')));
..houseMap = (json['houseMap'] as Map<String, dynamic>).map((k, e) =>
new MapEntry(
k, House.values.singleWhere((x) => x.toString() == 'House.$e')));

abstract class _$PersonSerializerMixin {
String get firstName;
Expand All @@ -37,8 +36,8 @@ abstract class _$PersonSerializerMixin {
'dateOfBirth': dateOfBirth.toIso8601String(),
r'$house': house.toString().split('.')[1],
'order': order,
'houseMap': new Map<String, dynamic>.fromIterables(houseMap.keys,
houseMap.values.map((e) => e.toString().split('.')[1]))
'houseMap':
houseMap.map((k, e) => new MapEntry(k, e.toString().split('.')[1]))
};
}

Expand All @@ -50,11 +49,8 @@ Order _$OrderFromJson(Map<String, dynamic> json) => new Order(
..count = json['count'] as int
..isRushed = json['isRushed'] as bool
..platform = new Platform.fromJson(json['platform'] as String)
..altPlatforms = new Map<String, Platform>.fromIterables(
(json['altPlatforms'] as Map<String, dynamic>).keys,
(json['altPlatforms'] as Map)
.values
.map((e) => new Platform.fromJson(e as String)));
..altPlatforms = (json['altPlatforms'] as Map<String, dynamic>)
.map((k, e) => new MapEntry(k, new Platform.fromJson(e as String)));

abstract class _$OrderSerializerMixin {
int get count;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,9 @@ Person _$PersonFromJson(Map<String, dynamic> json) => new Person(
middleName: json['middleName'] as String,
dateOfBirth: DateTime.parse(json['dateOfBirth'] as String))
..order = new Order.fromJson(json['order'] as Map<String, dynamic>)
..houseMap = new Map<String, House>.fromIterables(
(json['houseMap'] as Map<String, dynamic>).keys,
(json['houseMap'] as Map).values.map(
(e) => House.values.singleWhere((x) => x.toString() == 'House.$e')));
..houseMap = (json['houseMap'] as Map<String, dynamic>).map((k, e) =>
new MapEntry(
k, House.values.singleWhere((x) => x.toString() == 'House.$e')));

abstract class _$PersonSerializerMixin {
String get firstName;
Expand Down Expand Up @@ -81,11 +80,8 @@ Order _$OrderFromJson(Map<String, dynamic> json) => new Order(
..count = json['count'] as int
..isRushed = json['isRushed'] as bool
..platform = new Platform.fromJson(json['platform'] as String)
..altPlatforms = new Map<String, Platform>.fromIterables(
(json['altPlatforms'] as Map<String, dynamic>).keys,
(json['altPlatforms'] as Map)
.values
.map((e) => new Platform.fromJson(e as String)));
..altPlatforms = (json['altPlatforms'] as Map<String, dynamic>)
.map((k, e) => new MapEntry(k, new Platform.fromJson(e as String)));

abstract class _$OrderSerializerMixin {
int get count;
Expand Down
17 changes: 6 additions & 11 deletions json_serializable/test/test_files/json_test_example.wrapped.g.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,10 @@ Person _$PersonFromJson(Map<String, dynamic> json) => new Person(
..order = json['order'] == null
? null
: new Order.fromJson(json['order'] as Map<String, dynamic>)
..houseMap = json['houseMap'] == null
? null
: new Map<String, House>.fromIterables(
(json['houseMap'] as Map<String, dynamic>).keys,
(json['houseMap'] as Map).values.map((e) => e == null
..houseMap = (json['houseMap'] as Map<String, dynamic>)?.map((k, e) =>
new MapEntry(
k,
e == null
? null
: House.values.singleWhere((x) => x.toString() == 'House.$e')));

Expand Down Expand Up @@ -93,12 +92,8 @@ Order _$OrderFromJson(Map<String, dynamic> json) => new Order(
..platform = json['platform'] == null
? null
: new Platform.fromJson(json['platform'] as String)
..altPlatforms = json['altPlatforms'] == null
? null
: new Map<String, Platform>.fromIterables(
(json['altPlatforms'] as Map<String, dynamic>).keys,
(json['altPlatforms'] as Map).values.map(
(e) => e == null ? null : new Platform.fromJson(e as String)));
..altPlatforms = (json['altPlatforms'] as Map<String, dynamic>)?.map((k, e) =>
new MapEntry(k, e == null ? null : new Platform.fromJson(e as String)));

abstract class _$OrderSerializerMixin {
int get count;
Expand Down
4 changes: 2 additions & 2 deletions json_serializable/test/test_files/kitchen_sink.dart
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ class KitchenSink extends Object

Map map = _defaultMap();
Map<String, String> stringStringMap = _defaultMap();
Map<String, int> stringIntMap = _defaultMap();
Map<String, DateTime> stringDateTimeMap = _defaultMap();
Map<dynamic, int> dynamicIntMap = _defaultMap();
Map<Object, DateTime> objectDateTimeMap = _defaultMap();

@JsonKey(includeIfNull: false)
List<Map<String, Map<String, List<List<DateTime>>>>> crazyComplex =
Expand Down
56 changes: 21 additions & 35 deletions json_serializable/test/test_files/kitchen_sink.g.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,23 +32,16 @@ KitchenSink _$KitchenSinkFromJson(Map json) => new KitchenSink(
..stringStringMap = json['stringStringMap'] == null
? null
: new Map<String, String>.from(json['stringStringMap'] as Map)
..stringIntMap = json['stringIntMap'] == null
..dynamicIntMap = json['dynamicIntMap'] == null
? null
: new Map<String, int>.from(json['stringIntMap'] as Map)
..stringDateTimeMap = json['stringDateTimeMap'] == null
? null
: new Map<String, DateTime>.fromIterables(
(json['stringDateTimeMap'] as Map).keys.cast<String>(),
(json['stringDateTimeMap'] as Map)
.values
.map((e) => e == null ? null : DateTime.parse(e as String)))
: new Map<String, int>.from(json['dynamicIntMap'] as Map)
..objectDateTimeMap = (json['objectDateTimeMap'] as Map)?.map(
(k, e) => new MapEntry(k, e == null ? null : DateTime.parse(e as String)))
..crazyComplex = (json['crazyComplex'] as List)
?.map((e) => e == null
? null
: new Map<String, Map<String, List<List<DateTime>>>>.fromIterables(
(e as Map).keys.cast<String>(),
(e as Map).values.map((e) =>
e == null ? null : new Map<String, List<List<DateTime>>>.fromIterables((e as Map).keys.cast<String>(), (e as Map).values.map((e) => (e as List)?.map((e) => (e as List)?.map((e) => e == null ? null : DateTime.parse(e as String))?.toList())?.toList())))))
?.map((e) => (e as Map)?.map((k, e) => new MapEntry(
k as String,
(e as Map)?.map(
(k, e) => new MapEntry(k as String, (e as List)?.map((e) => (e as List)?.map((e) => e == null ? null : DateTime.parse(e as String))?.toList())?.toList())))))
?.toList()
..val = json['val'] == null ? null : new Map<String, bool>.from(json['val'] as Map)
..writeNotNull = json['writeNotNull'] as bool
Expand All @@ -70,8 +63,8 @@ abstract class _$KitchenSinkSerializerMixin {
List<DateTime> get dateTimeList;
Map<dynamic, dynamic> get map;
Map<String, String> get stringStringMap;
Map<String, int> get stringIntMap;
Map<String, DateTime> get stringDateTimeMap;
Map<dynamic, int> get dynamicIntMap;
Map<Object, DateTime> get objectDateTimeMap;
List<Map<String, Map<String, List<List<DateTime>>>>> get crazyComplex;
Map<String, bool> get val;
bool get writeNotNull;
Expand Down Expand Up @@ -103,27 +96,20 @@ abstract class _$KitchenSinkSerializerMixin {
dateTimeList?.map((e) => e?.toIso8601String())?.toList());
val['map'] = map;
val['stringStringMap'] = stringStringMap;
val['stringIntMap'] = stringIntMap;
val['stringDateTimeMap'] = stringDateTimeMap == null
? null
: new Map<String, dynamic>.fromIterables(stringDateTimeMap.keys,
stringDateTimeMap.values.map((e) => e?.toIso8601String()));
val['dynamicIntMap'] = dynamicIntMap;
val['objectDateTimeMap'] =
objectDateTimeMap?.map((k, e) => new MapEntry(k, e?.toIso8601String()));
writeNotNull(
'crazyComplex',
crazyComplex
?.map((e) => e == null
? null
: new Map<String, dynamic>.fromIterables(
e.keys,
e.values.map((e) => e == null
? null
: new Map<String, dynamic>.fromIterables(
e.keys,
e.values.map((e) => e
?.map((e) => e
?.map((e) => e?.toIso8601String())
?.toList())
?.toList())))))
?.map((e) => e?.map((k, e) => new MapEntry(
k,
e?.map((k, e) => new MapEntry(
k,
e
?.map((e) =>
e?.map((e) => e?.toIso8601String())?.toList())
?.toList())))))
?.toList());
writeNotNull('val', this.val);
val['writeNotNull'] = this.writeNotNull;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ class KitchenSink extends Object

Map map = _defaultMap();
Map<String, String> stringStringMap = _defaultMap();
Map<String, int> stringIntMap = _defaultMap();
Map<String, DateTime> stringDateTimeMap = _defaultMap();
Map<dynamic, int> dynamicIntMap = _defaultMap();
Map<Object, DateTime> objectDateTimeMap = _defaultMap();

@JsonKey(includeIfNull: false)
List<Map<String, Map<String, List<List<DateTime>>>>> crazyComplex =
Expand Down
Loading