From 99a0b39da7bf87d81784137e4fb6d6ef05a01646 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Tue, 20 Jun 2017 20:49:27 -0700 Subject: [PATCH 1/8] Add Iterable and List test examples --- test/test_files/json_test_example.dart | 9 ++++++++ test/test_files/json_test_example.g.dart | 28 ++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/test/test_files/json_test_example.dart b/test/test_files/json_test_example.dart index 09fa4d72..25cebf26 100644 --- a/test/test_files/json_test_example.dart +++ b/test/test_files/json_test_example.dart @@ -11,6 +11,15 @@ import 'package:source_gen/generators/json_serializable.dart'; part 'json_test_example.g.dart'; +@JsonSerializable() +class ListGenericTests { + Iterable iterable; + Iterable dynamicIterable; + Iterable objectIterable; + Iterable intIterable; + Iterable dateTimeIterable; +} + @JsonSerializable() class Person extends Object with _$PersonSerializerMixin { final String firstName, middleName, lastName; diff --git a/test/test_files/json_test_example.g.dart b/test/test_files/json_test_example.g.dart index 2adb3fa1..a56ba5b7 100644 --- a/test/test_files/json_test_example.g.dart +++ b/test/test_files/json_test_example.g.dart @@ -2,6 +2,34 @@ part of source_gen.test.example; +// ************************************************************************** +// Generator: JsonSerializableGenerator +// Target: class ListGenericTests +// ************************************************************************** + +ListGenericTests _$ListGenericTestsFromJson(Map json) => new ListGenericTests() + ..iterable = (json['iterable'] as List)?.map((v0) => v0) + ..dynamicIterable = (json['dynamicIterable'] as List)?.map((v0) => v0) + ..objectIterable = (json['objectIterable'] as List)?.map((v0) => v0 as Object) + ..intIterable = (json['intIterable'] as List)?.map((v0) => v0 as int) + ..dateTimeIterable = (json['dateTimeIterable'] as List) + ?.map((v0) => v0 == null ? null : DateTime.parse(v0)); + +abstract class _$ListGenericTestsSerializerMixin { + Iterable get iterable; + Iterable get dynamicIterable; + Iterable get objectIterable; + Iterable get intIterable; + Iterable get dateTimeIterable; + Map toJson() => { + 'iterable': iterable, + 'dynamicIterable': dynamicIterable, + 'objectIterable': objectIterable, + 'intIterable': intIterable, + 'dateTimeIterable': dateTimeIterable + }; +} + // ************************************************************************** // Generator: JsonSerializableGenerator // Target: class Person From 188b8762d6c2f2cac09cae4797fd34aa81511f8d Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Tue, 20 Jun 2017 19:00:32 -0700 Subject: [PATCH 2/8] Remove gratuitous List optimization --- lib/generators/json_serializable_generator.dart | 16 +++++----------- test/test_files/json_test_example.g.dart | 5 +---- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/lib/generators/json_serializable_generator.dart b/lib/generators/json_serializable_generator.dart index 16c7f205..11f0f3d6 100644 --- a/lib/generators/json_serializable_generator.dart +++ b/lib/generators/json_serializable_generator.dart @@ -205,22 +205,16 @@ class JsonSerializableGenerator } if (_coreListChecker.isAssignableFromType(fieldType)) { - var indexVal = "i${depth}"; - - var substitute = '${expression}[$indexVal]'; + var substitute = "v$depth"; var subFieldValue = _fieldToJsonMapValue(substitute, _getIterableGenericType(fieldType as InterfaceType), depth + 1); - // If we're dealing with `List` where `T` must be serialized, then - // generate a value that does the equivalent of .map(...).toList(), but - // Does so efficiently by creating a known-length List. - //TODO(kevmoo) this might be overkill. I think .map on iterable returns - // an efficient-length iterable, so .map(...).toList() might be fine. :-/ + // In the case of trivial JSON types (int, String, etc), `subFieldValue` + // will be identical to `substitute` – so no explicit mapping is needed. + // If they are not equal, then we to write out the substitution. if (subFieldValue != substitute) { // TODO: the type could be imported from a library with a prefix! - return "${expression} == null ? null : " - "new List.generate(${expression}.length, " - "(int $indexVal) => $subFieldValue)"; + return "${expression}?.map(($substitute) => $subFieldValue)?.toList()"; } } diff --git a/test/test_files/json_test_example.g.dart b/test/test_files/json_test_example.g.dart index a56ba5b7..1daa7ccf 100644 --- a/test/test_files/json_test_example.g.dart +++ b/test/test_files/json_test_example.g.dart @@ -93,10 +93,7 @@ abstract class _$ItemSerializerMixin { Map toJson() => { 'price': price, 'itemNumber': itemNumber, - 'saleDates': saleDates == null - ? null - : new List.generate( - saleDates.length, (int i0) => saleDates[i0]?.toIso8601String()), + 'saleDates': saleDates?.map((v0) => v0?.toIso8601String())?.toList(), 'rates': rates }; } From 42fa2127c1fac158e6e512f4d41308e57f2caab8 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Tue, 20 Jun 2017 19:21:02 -0700 Subject: [PATCH 3/8] JSON: Write abstract properties with generic types --- example/example.g.dart | 2 +- lib/generators/json_serializable_generator.dart | 3 +-- test/test_files/json_test_example.g.dart | 16 ++++++++-------- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/example/example.g.dart b/example/example.g.dart index 880685df..c8782934 100644 --- a/example/example.g.dart +++ b/example/example.g.dart @@ -22,7 +22,7 @@ abstract class _$PersonSerializerMixin { String get middleName; String get lastName; DateTime get dateOfBirth; - List get orders; + List get orders; Map toJson() => { 'firstName': firstName, 'middleName': middleName, diff --git a/lib/generators/json_serializable_generator.dart b/lib/generators/json_serializable_generator.dart index 11f0f3d6..143e948c 100644 --- a/lib/generators/json_serializable_generator.dart +++ b/lib/generators/json_serializable_generator.dart @@ -88,8 +88,7 @@ class JsonSerializableGenerator // write fields fields.forEach((name, field) { //TODO - handle aliased imports - //TODO - write generic types. Now `List` turns into `List` - buffer.writeln(' ${field.type.name} get $name;'); + buffer.writeln(' ${field.type} get $name;'); }); // write toJson method diff --git a/test/test_files/json_test_example.g.dart b/test/test_files/json_test_example.g.dart index 1daa7ccf..53974782 100644 --- a/test/test_files/json_test_example.g.dart +++ b/test/test_files/json_test_example.g.dart @@ -16,11 +16,11 @@ ListGenericTests _$ListGenericTestsFromJson(Map json) => new ListGenericTests() ?.map((v0) => v0 == null ? null : DateTime.parse(v0)); abstract class _$ListGenericTestsSerializerMixin { - Iterable get iterable; - Iterable get dynamicIterable; - Iterable get objectIterable; - Iterable get intIterable; - Iterable get dateTimeIterable; + Iterable get iterable; + Iterable get dynamicIterable; + Iterable get objectIterable; + Iterable get intIterable; + Iterable get dateTimeIterable; Map toJson() => { 'iterable': iterable, 'dynamicIterable': dynamicIterable, @@ -68,7 +68,7 @@ Order _$OrderFromJson(Map json) => new Order((json['items'] as List) abstract class _$OrderSerializerMixin { int get count; bool get isRushed; - UnmodifiableListView get items; + UnmodifiableListView get items; Map toJson() => {'count': count, 'isRushed': isRushed, 'items': items}; } @@ -88,8 +88,8 @@ Item _$ItemFromJson(Map json) => new Item(json['price'] as int) abstract class _$ItemSerializerMixin { int get price; int get itemNumber; - List get saleDates; - List get rates; + List get saleDates; + List get rates; Map toJson() => { 'price': price, 'itemNumber': itemNumber, From 472597a6bd3c725333bf4a261e1fd8b964149a60 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Wed, 21 Jun 2017 09:06:47 -0700 Subject: [PATCH 4/8] add more test list fields --- test/test_files/json_test_example.dart | 6 ++++++ test/test_files/json_test_example.g.dart | 23 +++++++++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/test/test_files/json_test_example.dart b/test/test_files/json_test_example.dart index 25cebf26..ec14a663 100644 --- a/test/test_files/json_test_example.dart +++ b/test/test_files/json_test_example.dart @@ -18,6 +18,12 @@ class ListGenericTests { Iterable objectIterable; Iterable intIterable; Iterable dateTimeIterable; + + List list; + List dynamicList; + List objectList; + List intList; + List dateTimeList; } @JsonSerializable() diff --git a/test/test_files/json_test_example.g.dart b/test/test_files/json_test_example.g.dart index 53974782..fe7ac256 100644 --- a/test/test_files/json_test_example.g.dart +++ b/test/test_files/json_test_example.g.dart @@ -13,7 +13,15 @@ ListGenericTests _$ListGenericTestsFromJson(Map json) => new ListGenericTests() ..objectIterable = (json['objectIterable'] as List)?.map((v0) => v0 as Object) ..intIterable = (json['intIterable'] as List)?.map((v0) => v0 as int) ..dateTimeIterable = (json['dateTimeIterable'] as List) - ?.map((v0) => v0 == null ? null : DateTime.parse(v0)); + ?.map((v0) => v0 == null ? null : DateTime.parse(v0)) + ..list = (json['list'] as List)?.map((v0) => v0)?.toList() + ..dynamicList = (json['dynamicList'] as List)?.map((v0) => v0)?.toList() + ..objectList = + (json['objectList'] as List)?.map((v0) => v0 as Object)?.toList() + ..intList = (json['intList'] as List)?.map((v0) => v0 as int)?.toList() + ..dateTimeList = (json['dateTimeList'] as List) + ?.map((v0) => v0 == null ? null : DateTime.parse(v0)) + ?.toList(); abstract class _$ListGenericTestsSerializerMixin { Iterable get iterable; @@ -21,12 +29,23 @@ abstract class _$ListGenericTestsSerializerMixin { Iterable get objectIterable; Iterable get intIterable; Iterable get dateTimeIterable; + List get list; + List get dynamicList; + List get objectList; + List get intList; + List get dateTimeList; Map toJson() => { 'iterable': iterable, 'dynamicIterable': dynamicIterable, 'objectIterable': objectIterable, 'intIterable': intIterable, - 'dateTimeIterable': dateTimeIterable + 'dateTimeIterable': dateTimeIterable, + 'list': list, + 'dynamicList': dynamicList, + 'objectList': objectList, + 'intList': intList, + 'dateTimeList': + dateTimeList?.map((v0) => v0?.toIso8601String())?.toList() }; } From 10728d1f76183acdf11edffeeab8001e29734991 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Wed, 21 Jun 2017 09:10:19 -0700 Subject: [PATCH 5/8] JSON: Avoid gratuitous list conversion while deserializing --- lib/generators/json_serializable_generator.dart | 8 +++++++- test/test_files/json_test_example.g.dart | 13 ++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/lib/generators/json_serializable_generator.dart b/lib/generators/json_serializable_generator.dart index 143e948c..fc3d402e 100644 --- a/lib/generators/json_serializable_generator.dart +++ b/lib/generators/json_serializable_generator.dart @@ -245,6 +245,12 @@ class JsonSerializableGenerator _getIterableGenericType(searchType as InterfaceType); var itemVal = "v$depth"; + var itemSubVal = + _writeAccessToVar(itemVal, iterableGenericType, depth: depth + 1); + + if (itemVal == itemSubVal) { + return varExpression; + } var output = "($varExpression as List)?.map(($itemVal) => " "${_writeAccessToVar(itemVal, iterableGenericType, depth: depth+1)}" @@ -257,7 +263,7 @@ class JsonSerializableGenerator return output; } - if (!searchType.isDynamic) { + if (!searchType.isDynamic && !searchType.isObject) { return "$varExpression as $searchType"; } diff --git a/test/test_files/json_test_example.g.dart b/test/test_files/json_test_example.g.dart index fe7ac256..74e37d45 100644 --- a/test/test_files/json_test_example.g.dart +++ b/test/test_files/json_test_example.g.dart @@ -8,16 +8,15 @@ part of source_gen.test.example; // ************************************************************************** ListGenericTests _$ListGenericTestsFromJson(Map json) => new ListGenericTests() - ..iterable = (json['iterable'] as List)?.map((v0) => v0) - ..dynamicIterable = (json['dynamicIterable'] as List)?.map((v0) => v0) - ..objectIterable = (json['objectIterable'] as List)?.map((v0) => v0 as Object) + ..iterable = json['iterable'] + ..dynamicIterable = json['dynamicIterable'] + ..objectIterable = json['objectIterable'] ..intIterable = (json['intIterable'] as List)?.map((v0) => v0 as int) ..dateTimeIterable = (json['dateTimeIterable'] as List) ?.map((v0) => v0 == null ? null : DateTime.parse(v0)) - ..list = (json['list'] as List)?.map((v0) => v0)?.toList() - ..dynamicList = (json['dynamicList'] as List)?.map((v0) => v0)?.toList() - ..objectList = - (json['objectList'] as List)?.map((v0) => v0 as Object)?.toList() + ..list = json['list'] + ..dynamicList = json['dynamicList'] + ..objectList = json['objectList'] ..intList = (json['intList'] as List)?.map((v0) => v0 as int)?.toList() ..dateTimeList = (json['dateTimeList'] as List) ?.map((v0) => v0 == null ? null : DateTime.parse(v0)) From 5c238c85f5dc29709e282450bc9c8834edb95058 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Wed, 21 Jun 2017 09:16:34 -0700 Subject: [PATCH 6/8] Fix analysis --- test/test_files/json_test_example.dart | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/test_files/json_test_example.dart b/test/test_files/json_test_example.dart index ec14a663..d420c410 100644 --- a/test/test_files/json_test_example.dart +++ b/test/test_files/json_test_example.dart @@ -12,7 +12,12 @@ import 'package:source_gen/generators/json_serializable.dart'; part 'json_test_example.g.dart'; @JsonSerializable() -class ListGenericTests { +class ListGenericTests extends Object with _$ListGenericTestsSerializerMixin { + ListGenericTests(); + + factory ListGenericTests.fromJson(Map json) => + _$ListGenericTestsFromJson(json); + Iterable iterable; Iterable dynamicIterable; Iterable objectIterable; From c498396f77c914b1b30f9cfc5df28b565b85155a Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Wed, 21 Jun 2017 09:28:19 -0700 Subject: [PATCH 7/8] updates --- .../json_serializable_generator.dart | 18 ++++++++++++++++-- test/test_files/json_test_example.g.dart | 11 ++++++----- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/lib/generators/json_serializable_generator.dart b/lib/generators/json_serializable_generator.dart index fc3d402e..e322a9a1 100644 --- a/lib/generators/json_serializable_generator.dart +++ b/lib/generators/json_serializable_generator.dart @@ -203,7 +203,11 @@ class JsonSerializableGenerator } } - if (_coreListChecker.isAssignableFromType(fieldType)) { + var isList = false; + if (_coreIterableChecker.isAssignableFromType(fieldType)) { + if (_coreListChecker.isAssignableFromType(fieldType)) { + isList = true; + } var substitute = "v$depth"; var subFieldValue = _fieldToJsonMapValue(substitute, _getIterableGenericType(fieldType as InterfaceType), depth + 1); @@ -213,10 +217,19 @@ class JsonSerializableGenerator // If they are not equal, then we to write out the substitution. if (subFieldValue != substitute) { // TODO: the type could be imported from a library with a prefix! - return "${expression}?.map(($substitute) => $subFieldValue)?.toList()"; + expression = "${expression}?.map(($substitute) => $subFieldValue)"; + + // expression now represents an Iterable (even if it started as a List + // ...resetting `isList` to `false`. + isList = false; } } + if (!isList && _coreIterableChecker.isAssignableFromType(fieldType)) { + // Then we need to add `?.toList() + expression += "?.toList()"; + } + return expression; } @@ -248,6 +261,7 @@ class JsonSerializableGenerator var itemSubVal = _writeAccessToVar(itemVal, iterableGenericType, depth: depth + 1); + // If `itemSubVal` is the same, then we don't need to do anything fancy if (itemVal == itemSubVal) { return varExpression; } diff --git a/test/test_files/json_test_example.g.dart b/test/test_files/json_test_example.g.dart index 74e37d45..344832d5 100644 --- a/test/test_files/json_test_example.g.dart +++ b/test/test_files/json_test_example.g.dart @@ -34,11 +34,12 @@ abstract class _$ListGenericTestsSerializerMixin { List get intList; List get dateTimeList; Map toJson() => { - 'iterable': iterable, - 'dynamicIterable': dynamicIterable, - 'objectIterable': objectIterable, - 'intIterable': intIterable, - 'dateTimeIterable': dateTimeIterable, + 'iterable': iterable?.toList(), + 'dynamicIterable': dynamicIterable?.toList(), + 'objectIterable': objectIterable?.toList(), + 'intIterable': intIterable?.toList(), + 'dateTimeIterable': + dateTimeIterable?.map((v0) => v0?.toIso8601String())?.toList(), 'list': list, 'dynamicList': dynamicList, 'objectList': objectList, From c787a46d9bb80e0b8cd6fad358b6d441e5d79fce Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Wed, 21 Jun 2017 09:56:46 -0700 Subject: [PATCH 8/8] test fix --- test/json_serializable_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/json_serializable_test.dart b/test/json_serializable_test.dart index fc29dd31..a06a2dad 100644 --- a/test/json_serializable_test.dart +++ b/test/json_serializable_test.dart @@ -94,7 +94,7 @@ void main() { await _getClassForCodeString('ParentObjectWithDynamicChildren'); var output = await _generator.generate(element, null); - expect(output, contains('(json[\'children\'] as List)?.map(')); + expect(output, contains('children = json[\'children\'];')); }); test('class with list of int is cast for strong mode', () async {