Description
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