google / google/json_serializable.dart

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

Open
#1,126 1 comment 13 reactions 0 assignees View on GitHub
Next breaking change release Type: enhancement
Dominant language
Dart
Stars
1.6k
Forks
461
Avg merge
45m
Merged PRs (30d)
1

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:

```dart
@JsonSerializable
class Root {
final Child child;
}

@JsonSerializable
class Child {
final String name;
}
```

I was thinking that instead of having:

```dart
Map _$RootToJson(Root value) {
return {'child': value.child};
}
```

we could have:

```dart
Map _$RootToJson(Root value) {
return {'child': value.child.toJson()};
}

Map _$ChildToJson(Child value) {
return LazyJsonMap(() => {'name': value.name});
}
```

Where the source of `LazyJsonMap` is:

```dart
class LazyJsonMap with MapMixin {
LazyJsonMap(this._toJson);

final Map Function() _toJson;

late final Map _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 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

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.