Skip to content

Proposal: Update explicitToJson:false to use still be lazy but return a custom collection instance #1126

Open
@rrousselGit

Description

@rrousselGit

The current behavior of explicitToJson: false seems problematic, as the output of toJson does not respect the JSON contract – which is allowing only List/Map/num/bool/String

While dart:convert supports it, there are alternatives that do not. Meaning that those alternatives will throw exceptions when receiving the output of a json_serializable's toJson. This is confusing to users, as error messages tend to be cryptic. And it ends up with users disabling explicitToJson globally, decreasing the value of this feature quite a bit.

Proposal

Would it be possible to update explicitToJson to render valid JSON output, while preserving the laziness of the encoding?

Say we have:

@JsonSerializable
class Root {
  final Child child;
}

@JsonSerializable
class Child {
  final String name;
}

I was thinking that instead of having:

Map<String, dynamic> _$RootToJson(Root value) {
  return {'child': value.child};
}

we could have:

Map<String, dynamic> _$RootToJson(Root value) {
  return {'child': value.child.toJson()};
}

Map<String, dynamic> _$ChildToJson(Child value) {
  return LazyJsonMap(() => {'name': value.name});
}

Where the source of LazyJsonMap is:

class LazyJsonMap with MapMixin<String, Object?> {
  LazyJsonMap(this._toJson);

  final Map<String, Object?> Function() _toJson;

  late final Map<String, Object?> _map = _toJson();

  @override
  Object? operator [](Object? key) => _map[key];

  @override
  void operator []=(String key, Object? value) => _map[key] = value;

  @override
  void clear() => _map.clear();

  @override
  Iterable<String> get keys => _map.keys;

  @override
  Object? remove(Object? key) => _map.remove(key);
}

By doing so, the serialization would still be lazy. But at the same time, if passed to encoders other than dart:convert, the output of toJson will no-longer throw – as LazyJsonMap is a valid Map instance

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions