Description
flutter --version
output:
Flutter 3.10.5 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 796c8ef792 (5 months ago) • 2023-06-13 15:51:02 -0700
Engine • revision 45f6e00911
Tools • Dart 3.0.5 • DevTools 2.23.1
My issue is basically the same as #538 , but I am not satisfied with the reasoning for closing the issue.
Suppose I have two classes, a parent class:
import 'package:json_annotation/json_annotation.dart';
import 'package:playground/child_object.dart';
part 'parent_object.g.dart';
@JsonSerializable(explicitToJson: true)
class ParentObject {
@JsonKey(name: 'child')
final ChildObject? child;
ParentObject({this.child});
factory ParentObject.fromJson(Map<String, dynamic> json) => _$ParentObjectFromJson(json);
Map<String, dynamic> toJson() => _$ParentObjectToJson(this);
}
and a child class:
import 'package:json_annotation/json_annotation.dart';
part 'child_object.g.dart';
@JsonSerializable(explicitToJson: true)
class ChildObject {
@JsonKey(name: 'testString')
final String? testString;
ChildObject({this.testString});
factory ChildObject.fromJson(Map<String, dynamic> json) => _$ChildObjectFromJson(json);
Map<String, dynamic> toJson() => _$ChildObjectToJson(this);
}
If I try to convert
Map<String, dynamic> testJson = {
"child": {}
};
via ParentObject.fromJson(testJson);
into my class I get the following exception:
Unhandled exception:
type '_Map<dynamic, dynamic>' is not a subtype of type 'Map<String, dynamic>' in type cast
#0 _$ParentObjectFromJson (package:playground/parent_object.g.dart:12:48)
#1 new ParentObject.fromJson (package:playground/parent_object.dart:14:63)
#2 main (package:playground/main.dart:4:31)
#3 _delayEntrypointInvocation. (dart:isolate-patch/isolate_patch.dart:296:19)
#4 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:189:12)
because an empty {}
is per default of type Map<dynamic, dynamic> and the cast in the autogenerated file subsequently throws an exception
ParentObject _$ParentObjectFromJson(Map<String, dynamic> json) => ParentObject(
child: json['child'] == null
? null
: ChildObject.fromJson(json['child'] as Map<String, dynamic>),
);
Since my testJson
is in a valid json format I do not think it is reasonable to expect the backend to change (which was the reasoning why issue #538 was closed).
If I change the autogenerated code and add an explicit cast
ParentObject _$ParentObjectFromJson(Map<String, dynamic> json) => ParentObject(
child: json['child'] == null
? null
: ChildObject.fromJson((json['child'] as Map).cast<String, dynamic>()),
);
it seems to work and my result is a ParentObject with an ChildObject, where the 'testString' field in the ChildObject is null.
Additionally one could add a treatEmptyAsNull
property as suggested in #538
If I change the autogenerated code and add a check to see if the map is empty
ParentObject _$ParentObjectFromJson(Map<String, dynamic> json) => ParentObject(
child: json['child'] == null || (json['child'] as Map).isEmpty
? null
: ChildObject.fromJson((json['child'] as Map).cast<String, dynamic>()),
);
my result is a ParentObject where its ChildObject has value null
Are there any issues I don't recognize with the solutions I provide? Or is it possible to adapt the autogenerated code so that it can handle empty json objects
Thanks in advance