google / google/json_serializable.dart

[bug] json_serializable is unable to recognize generics on `@JsonKey`'s `toJson/fromJson` methods, or on `JsonConverter`

Open
#1,508 1 comment 4 reactions 0 assignees View on GitHub
Dominant language
Dart
Stars
1.6k
Forks
461
Avg merge
45m
Merged PRs (30d)
1

Description

TL;DR: minimal reproducible bug:
```dart
class A {}

A fromJson(String input) => A();
String toJson(A input) => '$input';

@JsonSerializable()
class Serializable {
const Serializable({required this.a});
@JsonKey(fromJson: fromJson, toJson: toJson)
final A a;
}
```
The above breaks the builder.

---

In an attempt to work around #1507, I end up with the following:

```dart
sealed class Slug {}
class Asd extends Slug {}
class Lol extends Slug {}
class Rofl extends Slug {}
class Lmao extends Slug<(int, int)> {}

@JsonSerializable()
class Serializable {
const Serializable(this.slug);
final Slug slug;
}
```

The above outputs:
```sh
[SEVERE] json_serializable on lib/src/features/models/lol_dto.dart:

Could not generate `fromJson` code for `slug`.
To support the type `Slug` you can:
* Use `JsonConverter`
https://pub.dev/documentation/json_annotation/latest/json_annotation/JsonConverter-class.html
* Use `JsonKey` fields `fromJson` and `toJson`
https://pub.dev/documentation/json_annotation/latest/json_annotation/JsonKey/fromJson.html
https://pub.dev/documentation/json_annotation/latest/json_annotation/JsonKey/toJson.html
package:asdlol/src/features/models/lol_dto.dart:19:17

19 │ final Slug slug;
│ ^^^^

```

**But that's expected**.

So, I follow the first advice, the `JsonConverter` way.
```dart
@JsonSerializable()
class Serializable {
const Serializable(this.slug);
@SlugConverter() // this has been added
final Slug slug;
}

class SlugConverter extends JsonConverter, String> {
const SlugConverter();

@override
String toJson(Slug object) {
return object.runtimeType.toString();
}

@override
Slug fromJson(String json) {
switch (json) {
case 'Asd':
return Asd() as Slug;
case 'Lol':
return Lol() as Slug;
case 'Rofl':
return Rofl() as Slug;
case 'Lmao':
return Lmao() as Slug;
default:
throw Exception('Unknown slug type: $json');
}
}
}
```

But the above is straight ignored by the builder, which outputs exactly the same message.
Am I doing something wrong? If so, can I be welcomed with a more informative message? 😸

Then, I try the `JsonKey` way.
```dart
@JsonSerializable()
class Serializable {
const Serializable(this.slug);
@JsonKey(fromJson: slugFromJson, toJson: slugToJson) // let's try this one now
final Slug slug;
}

String slugToJson(Slug object) {
return object.runtimeType.toString();
}

Slug slugFromJson(String json) {
switch (json) {
case 'Asd':
return Asd() as Slug;
case 'Lol':
return Lol() as Slug;
case 'Rofl':
return Rofl() as Slug;
case 'Lmao':
return Lmao() as Slug;
default:
throw Exception('Unknown slug type: $json');
}
}
```

But the above leads the builder to output:
```sh
[SEVERE] json_serializable on lib/src/features/models/lol_dto.dart:

Error with `@JsonKey` on the `slug` field. The `toJson` function `slugToJson` argument type `Slug` is not compatible with field type `Slug`.
package:asdlol/src/features/models/lol_dto.dart:19:17

19 │ final Slug slug;
│ ^^^^

```

Say again? `Slug` is not compatible with `Slug`? 😵‍💫

I'm unsure what I can actually do at this point.

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.