Json codable no type assumption in custom fromJson

Closes https://github.com/dart-lang/sdk/pull/59581

GitOrigin-RevId: 8137077107f7f566213b8f09ddfc6610c194367a
Change-Id: I263a189a6ec181fa8a6e28d77efe20d0cec0629b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/396629
Reviewed-by: Jake Macdonald <jakemac@google.com>
Commit-Queue: Jake Macdonald <jakemac@google.com>
This commit is contained in:
cedvdb
2024-12-02 18:40:22 +00:00
committed by Commit Queue
parent e013a4c9bf
commit 56b6e5b9f6
4 changed files with 147 additions and 5 deletions
+4
View File
@@ -1,3 +1,7 @@
# 0.20.4
- Allow custom `fromJson` to have an arbitrary parameter type.
# 0.20.3
- Add support for DateTime, serializing it to an ISO-8601 String.
+4 -4
View File
@@ -394,16 +394,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,
')',
]);
}
+1 -1
View File
@@ -5,7 +5,7 @@ description: >
`toJson` encoding method.
repository: https://github.com/dart-lang/sdk/tree/main/pkg/json
version: 0.20.3
version: 0.20.4
environment:
sdk: ^3.6.0-edge
dependencies:
+138
View File
@@ -26,6 +26,11 @@ void main() {
'mapOfSerializableField': {
'c': {'x': 3}
},
'customStringSerializationField': 'hi',
'customNullableStringSerialization': null,
'customMapSerializationField': {
'z': 'zzz',
}
};
var a = A.fromJson(json);
@@ -38,6 +43,11 @@ 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.customNullableStringSerialization,
equals(CustomNullableStringSerialization(null)));
expect(
a.customMapSerializationField, CustomMapSerialization({'z': 'zzz'}));
expect(a.toJson(), equals(json));
});
@@ -59,6 +69,8 @@ void main() {
'nullableMapOfSerializableField': {
'd': {'x': 3},
},
'nullableCustomStringSerializationField': 'hi',
'nullableCustomMapSerializationField': {'z': 'zzz'},
};
var b = B.fromJson(json);
@@ -72,6 +84,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));
});
@@ -87,6 +103,8 @@ void main() {
'nullableListOfSerializableField': null,
'nullableSetOfSerializableField': null,
'nullableMapOfSerializableField': null,
'nullableCustomStringSerializationField': null,
'nullableCustomMapSerializationField': null,
});
expect(b.nullableBoolField, null);
expect(b.nullableStringField, null);
@@ -97,6 +115,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);
});
@@ -112,6 +132,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);
});
@@ -140,6 +162,11 @@ void main() {
null,
{'a': 1, 'b': null},
],
'listOfCustomStringSerializables': [null, 'hi'],
'listOfCustomMapSerializables': [
null,
{'z': 'zzz'},
],
'setOfNullableDates': [
null,
'2024-11-12T03:42:29.108308',
@@ -159,6 +186,11 @@ void main() {
'b': null,
},
],
'setOfCustomStringSerializables': [null, 'hi'],
'setOfCustomMapSerializables': [
null,
{'z': 'zzz'}
],
'mapOfNullableDates': {
'a': '2024-11-13T03:42:29.108308',
'b': null,
@@ -175,6 +207,14 @@ void main() {
'a': [null, 3],
'b': null,
},
'mapOfCustomStringSerializables': {
'a': null,
'b': 'hi',
},
'mapOfCustomMapSerializables': {
'a': null,
'b': {'z': 'zzz'},
},
};
var e = E.fromJson(json);
@@ -189,6 +229,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.setOfNullableDates,
equals([null, DateTime.parse('2024-11-12T03:42:29.108308')]));
expect(e.setOfNullableInts, equals({null, 2}));
@@ -203,6 +250,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.mapOfNullableDates,
equals({
@@ -222,6 +276,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));
});
@@ -257,6 +317,12 @@ class A {
final Set<C> setOfSerializableField;
final Map<String, C> mapOfSerializableField;
final CustomStringSerialization customStringSerializationField;
final CustomMapSerialization customMapSerializationField;
final CustomNullableStringSerialization customNullableStringSerialization;
}
@JsonCodable()
@@ -278,6 +344,10 @@ class B {
final Set<C>? nullableSetOfSerializableField;
final Map<String, C>? nullableMapOfSerializableField;
final CustomStringSerialization? nullableCustomStringSerializationField;
final CustomMapSerialization? nullableCustomMapSerializationField;
}
@JsonCodable()
@@ -300,6 +370,10 @@ class E {
final List<Map<String, int?>?> listOfNullableMapsOfNullableInts;
final List<CustomStringSerialization?> listOfCustomStringSerializables;
final List<CustomMapSerialization?> listOfCustomMapSerializables;
final Set<DateTime?> setOfNullableDates;
final Set<int?> setOfNullableInts;
@@ -308,6 +382,10 @@ class E {
final Set<Map<String, int?>?> setOfNullableMapsOfNullableInts;
final Set<CustomStringSerialization?> setOfCustomStringSerializables;
final Set<CustomMapSerialization?> setOfCustomMapSerializables;
final Map<String, DateTime?> mapOfNullableDates;
final Map<String, int?> mapOfNullableInts;
@@ -315,9 +393,69 @@ class E {
final Map<String, C?> mapOfNullableSerializables;
final Map<String, Set<int?>?> mapOfNullableSetsOfNullableInts;
final Map<String, CustomStringSerialization?> mapOfCustomStringSerializables;
final Map<String, CustomMapSerialization?> 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 CustomNullableStringSerialization {
final String? a;
CustomNullableStringSerialization(this.a);
String? toJson() => a;
factory CustomNullableStringSerialization.fromJson(String? a) =>
CustomNullableStringSerialization(a);
@override
bool operator ==(Object other) =>
other is CustomNullableStringSerialization && a == other.a;
@override
int get hashCode => a.hashCode;
}
class CustomMapSerialization {
final Map<String, dynamic> a;
CustomMapSerialization(this.a);
Map<String, dynamic> toJson() => a;
factory CustomMapSerialization.fromJson(Map<String, dynamic> a) =>
CustomMapSerialization(a);
@override
bool operator ==(Object other) {
return other is CustomMapSerialization &&
a.toString() == other.a.toString();
}
@override
int get hashCode => a.hashCode;
}