From ba39aa4ff094b6d862b8e032d82472a355e255cb Mon Sep 17 00:00:00 2001 From: cedvdb Date: Thu, 21 Nov 2024 12:31:48 +0100 Subject: [PATCH] remove map assumption in fromJson --- pkg/json/CHANGELOG.md | 3 + pkg/json/lib/json.dart | 8 +- pkg/json/pubspec.yaml | 2 +- pkg/json/test/json_codable_test.dart | 115 +++++++++++++++++++++++++++ 4 files changed, 123 insertions(+), 5 deletions(-) diff --git a/pkg/json/CHANGELOG.md b/pkg/json/CHANGELOG.md index cfbb0bad53f8..864a9dfda3c3 100644 --- a/pkg/json/CHANGELOG.md +++ b/pkg/json/CHANGELOG.md @@ -1,3 +1,6 @@ +# 0.20.3 +- Allow custom `fromJson` to have an arbitrary parameter type. + # 0.20.2 - Fix generated code syntax error when defining fields containing the dollar sign `$` by using raw strings. diff --git a/pkg/json/lib/json.dart b/pkg/json/lib/json.dart index bcf237f7a7aa..f72d6d696720 100644 --- a/pkg/json/lib/json.dart +++ b/pkg/json/lib/json.dart @@ -384,16 +384,16 @@ mixin _FromJson on _Shared { // Otherwise, check if `classDecl` has a `fromJson` constructor. final constructors = await builder.constructorsOf(classDecl); final fromJson = constructors - .firstWhereOrNull((c) => c.identifier.name == 'fromJson') - ?.identifier; + .firstWhereOrNull((c) => c.identifier.name == 'fromJson'); + if (fromJson != null) { return RawCode.fromParts([ if (nullCheck != null) nullCheck, - fromJson, + fromJson.identifier, '(', jsonReference, ' as ', - introspectionData.jsonMapCode, + fromJson.positionalParameters.first.type.code, ')', ]); } diff --git a/pkg/json/pubspec.yaml b/pkg/json/pubspec.yaml index 98a28ee251f4..e2eb306c0d6b 100644 --- a/pkg/json/pubspec.yaml +++ b/pkg/json/pubspec.yaml @@ -5,7 +5,7 @@ description: > `toJson` encoding method. repository: https://github.com/dart-lang/sdk/tree/main/pkg/json -version: 0.20.2 +version: 0.20.3 environment: sdk: ^3.6.0-edge dependencies: diff --git a/pkg/json/test/json_codable_test.dart b/pkg/json/test/json_codable_test.dart index b18c3320df33..d8cf783ead26 100644 --- a/pkg/json/test/json_codable_test.dart +++ b/pkg/json/test/json_codable_test.dart @@ -25,6 +25,10 @@ void main() { 'mapOfSerializableField': { 'c': {'x': 3} }, + 'customStringSerializationField': 'hi', + 'customMapSerializationField': { + 'z': 'zzz', + } }; var a = A.fromJson(json); @@ -36,6 +40,9 @@ void main() { expect(a.listOfSerializableField.single.x, 1); expect(a.setOfSerializableField.single.x, 2); expect(a.mapOfSerializableField['c']!.x, 3); + expect(a.customStringSerializationField, CustomStringSerialization('hi')); + expect( + a.customMapSerializationField, CustomMapSerialization({'z': 'zzz'})); expect(a.toJson(), equals(json)); }); @@ -56,6 +63,8 @@ void main() { 'nullableMapOfSerializableField': { 'd': {'x': 3}, }, + 'nullableCustomStringSerializationField': 'hi', + 'nullableCustomMapSerializationField': {'z': 'zzz'}, }; var b = B.fromJson(json); @@ -67,6 +76,10 @@ void main() { expect(b.nullableListOfSerializableField!.single.x, 1); expect(b.nullableSetOfSerializableField!.single.x, 2); expect(b.nullableMapOfSerializableField!['d']!.x, 3); + expect(b.nullableCustomStringSerializationField, + CustomStringSerialization('hi')); + expect(b.nullableCustomMapSerializationField, + CustomMapSerialization({'z': 'zzz'})); expect(b.toJson(), equals(json)); }); @@ -81,6 +94,8 @@ void main() { 'nullableListOfSerializableField': null, 'nullableSetOfSerializableField': null, 'nullableMapOfSerializableField': null, + 'nullableCustomStringSerializationField': null, + 'nullableCustomMapSerializationField': null, }); expect(b.nullableBoolField, null); expect(b.nullableStringField, null); @@ -90,6 +105,8 @@ void main() { expect(b.nullableListOfSerializableField, null); expect(b.nullableMapOfSerializableField, null); expect(b.nullableSetOfSerializableField, null); + expect(b.nullableCustomStringSerializationField, null); + expect(b.nullableCustomMapSerializationField, null); expect(b.toJson(), isEmpty); }); @@ -104,6 +121,8 @@ void main() { expect(b.nullableListOfSerializableField, null); expect(b.nullableMapOfSerializableField, null); expect(b.nullableSetOfSerializableField, null); + expect(b.nullableCustomStringSerializationField, null); + expect(b.nullableCustomMapSerializationField, null); expect(b.toJson(), isEmpty); }); @@ -131,6 +150,11 @@ void main() { null, {'a': 1, 'b': null}, ], + 'listOfCustomStringSerializables': [null, 'hi'], + 'listOfCustomMapSerializables': [ + null, + {'z': 'zzz'} + ], 'setOfNullableInts': [ null, 2, @@ -146,6 +170,11 @@ void main() { 'b': null, }, ], + 'setOfCustomStringSerializables': [null, 'hi'], + 'setOfCustomMapSerializables': [ + null, + {'z': 'zzz'} + ], 'mapOfNullableInts': { 'a': 3, 'b': null, @@ -158,6 +187,14 @@ void main() { 'a': [null, 3], 'b': null, }, + 'mapOfCustomStringSerializables': { + 'a': null, + 'b': 'hi', + }, + 'mapOfCustomMapSerializables': { + 'a': null, + 'b': {'z': 'zzz'}, + }, }; var e = E.fromJson(json); @@ -170,6 +207,13 @@ void main() { null, {'a': 1, 'b': null}, ])); + expect(e.listOfCustomStringSerializables.first, null); + expect(e.listOfCustomStringSerializables[1], + CustomStringSerialization('hi')); + expect(e.listOfCustomMapSerializables.first, null); + expect(e.listOfCustomMapSerializables[1], + CustomMapSerialization({'z': 'zzz'})); + expect(e.setOfNullableInts, equals({null, 2})); expect(e.setOfNullableSerializables.first!.x, 2); expect(e.setOfNullableSerializables.elementAt(1), null); @@ -182,6 +226,13 @@ void main() { 'b': null, }, })); + expect(e.setOfCustomStringSerializables.first, null); + expect(e.setOfCustomStringSerializables.toList()[1], + CustomStringSerialization('hi')); + expect(e.setOfCustomMapSerializables.first, null); + expect(e.setOfCustomMapSerializables.toList()[1], + CustomMapSerialization({'z': 'zzz'})); + expect( e.mapOfNullableInts, equals({ @@ -195,6 +246,12 @@ void main() { 'a': {null, 3}, 'b': null, }); + expect(e.mapOfCustomStringSerializables?['a'], null); + expect(e.mapOfCustomStringSerializables?['b'], + CustomStringSerialization('hi')); + expect(e.mapOfCustomMapSerializables?['a'], null); + expect(e.mapOfCustomMapSerializables?['b'], + CustomMapSerialization({'z': 'zzz'})); expect(e.toJson(), equals(json)); }); @@ -228,6 +285,10 @@ class A { final Set setOfSerializableField; final Map mapOfSerializableField; + + final CustomStringSerialization customStringSerializationField; + + final CustomMapSerialization customMapSerializationField; } @JsonCodable() @@ -247,6 +308,10 @@ class B { final Set? nullableSetOfSerializableField; final Map? nullableMapOfSerializableField; + + final CustomStringSerialization? nullableCustomStringSerializationField; + + final CustomMapSerialization? nullableCustomMapSerializationField; } @JsonCodable() @@ -267,20 +332,70 @@ class E { final List?> listOfNullableMapsOfNullableInts; + final List listOfCustomStringSerializables; + + final List listOfCustomMapSerializables; + final Set setOfNullableInts; final Set setOfNullableSerializables; final Set?> setOfNullableMapsOfNullableInts; + final Set setOfCustomStringSerializables; + + final Set setOfCustomMapSerializables; + final Map mapOfNullableInts; final Map mapOfNullableSerializables; final Map?> mapOfNullableSetsOfNullableInts; + + final Map mapOfCustomStringSerializables; + + final Map mapOfCustomMapSerializables; } @JsonCodable() class F { final int fieldWithDollarSign$; } + +class CustomStringSerialization { + final String a; + + CustomStringSerialization(this.a); + + String toJson() => a; + + factory CustomStringSerialization.fromJson(String a) => + CustomStringSerialization(a); + + @override + bool operator ==(Object other) => + other is CustomStringSerialization && a == other.a; + + @override + int get hashCode => a.hashCode; +} + +class CustomMapSerialization { + final Map a; + + CustomMapSerialization(this.a); + + Map toJson() => a; + + factory CustomMapSerialization.fromJson(Map a) => + CustomMapSerialization(a); + + @override + bool operator ==(Object other) { + return other is CustomMapSerialization && + a.toString() == other.a.toString(); + } + + @override + int get hashCode => a.hashCode; +}