Skip to content

Handling empty nested json objects #1370

Open
@blechlem

Description

@blechlem

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions