google / google/json_serializable.dart
Handling empty nested json objects
- Dominant language
- Dart
- Stars
- 1.6k
- Forks
- 461
- Avg merge
- 45m
- Merged PRs (30d)
- 1
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 json) => _$ParentObjectFromJson(json);
Map 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 json) => _$ChildObjectFromJson(json);
Map toJson() => _$ChildObjectToJson(this);
}
```
If I try to convert
```
Map testJson = {
"child": {}
};
```
via `ParentObject.fromJson(testJson);` into my class I get the following exception:
> Unhandled exception:
> type '_Map' is not a subtype of type 'Map' 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 and the cast in the autogenerated file subsequently throws an exception
```
ParentObject _$ParentObjectFromJson(Map json) => ParentObject(
child: json['child'] == null
? null
: ChildObject.fromJson(json['child'] as Map),
);
```
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 json) => ParentObject(
child: json['child'] == null
? null
: ChildObject.fromJson((json['child'] as Map).cast()),
);
```
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 json) => ParentObject(
child: json['child'] == null || (json['child'] as Map).isEmpty
? null
: ChildObject.fromJson((json['child'] as Map).cast()),
);
```
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
Contributor guide
Assessment
This issue has not been assessed yet.