Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generics complicate self-referential class structure #1415

Open
craiglabenz opened this issue Apr 22, 2024 · 4 comments
Open

Generics complicate self-referential class structure #1415

craiglabenz opened this issue Apr 22, 2024 · 4 comments

Comments

@craiglabenz
Copy link

The following code builds, but see the comment for which critical information has to be removed for said build to succeed:

class Base<T> {
  const Base();
}

class BaseConverter<T> extends JsonConverter<Base, Map<String, Object?>> {
  const BaseConverter();
  @override
  Map<String, Object?> toJson(Base object) => {};
  @override
  Base fromJson(Map<String, Object?> json) => Base();
}

@JsonSerializable()
class Data<T> extends Base<T> {
  Data({
    required this.data,
    required this.name,
  });

  factory Data.fromJson(Map<String, dynamic> json) => _$DataFromJson(json);

  final String name;

  @BaseConverter()
  // Ideally, this would be Base<T>, but defining it so breaks the build
  final Base data;

  Map<String, dynamic> toJson() => _$DataToJson(this);
}

Changing final Base data to final Base<T> data results in this error:

[SEVERE] json_serializable on lib/src/data.dart:

Could not generate `fromJson` code for `data`.
To support the type `Base` 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:json_serializable_test/src/data.dart:30:17
   ╷
[line number] │   final Base<T> data;

This despite the fact that a JsonConverter is clearly being used.

For posterity, I originally reported this at rrousselGit/freezed#1074, and was (correctly, it seems) directed here.

@i-panov
Copy link

i-panov commented Jun 10, 2024

I have same problem :c

@gnprice
Copy link

gnprice commented Jul 1, 2024

class BaseConverter<T> extends JsonConverter<Base, Map<String, Object?>> {

What happens if you write Base<T> there, instead of Base?

Writing just Base with no arguments is equivalent, IIUC, to writing Base<dynamic>. Which doesn't seem like what you intend. And it makes sense that a converter that produces a Base<dynamic> wouldn't be seen as a match when the field is supposed to hold more specifically a Base<T>.

That said, I won't be surprised if that doesn't fix it. Here's a possibly related issue:

which suggests that the logic for applying a JsonConverter doesn't currently do everything one would hope it would when there are type parameters involved.

@kevmoo
Copy link
Collaborator

kevmoo commented Aug 15, 2024

@craiglabenz – is this what you want?

diff --git a/json_serializable/test/generic_files/for_craig.dart b/json_serializable/test/generic_files/for_craig.dart
index 5555d80..bb0011e 100644
--- a/json_serializable/test/generic_files/for_craig.dart
+++ b/json_serializable/test/generic_files/for_craig.dart
@@ -6,12 +6,12 @@ class Base<T> {
   const Base();
 }

-class BaseConverter<T> extends JsonConverter<Base, Map<String, Object?>> {
+class BaseConverter<T> extends JsonConverter<Base<T>, Map<String, Object?>> {
   const BaseConverter();
   @override
   Map<String, Object?> toJson(Base object) => {};
   @override
-  Base fromJson(Map<String, Object?> json) => const Base();
+  Base<T> fromJson(Map<String, Object?> json) => Base<T>();
 }

 @JsonSerializable()
@@ -26,8 +26,7 @@ class Data<T> extends Base<T> {
   final String name;

   @BaseConverter()
-  // Ideally, this would be Base<T>, but defining it so breaks the build
-  final Base data;
+  final Base<T> data;

   Map<String, dynamic> toJson() => _$DataToJson(this);
 }

And instantiate BaseConverter with the right generic parameter?

@craiglabenz
Copy link
Author

Looks right, @kevmoo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants