Unable to generate fromJson() and toJson() for generics using freezed package

3.6k Views Asked by At

We are trying to create a generic Category class. At the time being, we are unsure whether category will have integer or UUID as key. Hence, we need the id to be generic for now. All works fine. However, we are unable to generate the fromJson() and toJson() using the freezed package.

import 'package:freezed_annotation/freezed_annotation.dart';

part 'category.freezed.dart';
part 'category.g.dart';

@freezed
@JsonSerializable(genericArgumentFactories: true)
class Category<T> with _$Category<T> {
  factory Category({
    required T id,
    required String name,
    required String imageUrl,
  }) = _Category;

  factory Category.fromJson(Map<String, dynamic> json) =>
      _$CategoryFromJson(json);
}

Error:

Could not generate `fromJson` code for `id` because of type `T` (type parameter).
To support type parameters (generic types) 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
* Set `JsonSerializable.genericArgumentFactories` to `true`
  https://pub.dev/documentation/json_annotation/latest/json_annotation/JsonSerializable/genericArgumentFactories.html
package:mobile/data/models/category.freezed.dart:144:11
    ╷
144 │   final T id;
    │           ^^
    ╵
[SEVERE] Failed after 2.4s
pub finished with exit code 1

As the error message suggests, I have used the @JsonSerializable(genericArgumentFactories: true) annotation however, it is not working as suggested. How can I get the fromJson() and toJson() methods with freezed for generics?

3

There are 3 best solutions below

0
On BEST ANSWER

Unsupported feature at the moment.

Source: Issue #616

1
On

If I'm not mistaken it's already supported: https://pub.dev/packages/freezed#deserializing-generic-classes

The only thing that you would need to adjust in your code is fromJson function to:

factory Category.fromJson(Map<String, dynamic> json, T Function(Object?) fromJsonT) => _$CategoryFromJson(json, fromJsonT);
0
On

Fixed using @JsonSerializable(genericArgumentFactories: true)

As per docs:

When true on classes with type parameters (generic types), extra "helper" parameters will be generated for fromJson and/or toJson to support serializing values of those types.

For example, the generated code for

@JsonSerializable(genericArgumentFactories: true)
class Response<T> {
  int status;
  T value;
}

Looks like

Response<T> _$ResponseFromJson<T>(
  Map<String, dynamic> json,
  T Function(Object json) fromJsonT,
) {
  return Response<T>()
    ..status = json['status'] as int
    ..value = fromJsonT(json['value']);
}

Map<String, dynamic> _$ResponseToJson<T>(
  Response<T> instance,
  Object Function(T value) toJsonT,
) =>
    <String, dynamic>{
      'status': instance.status,
      'value': toJsonT(instance.value),
    };

Notes:

  1. This option has no effect on classes without type parameters. If used on such a class, a warning is echoed in the build log.
  2. If this option is set for all classes in a package via build.yaml it is only applied to classes with type parameters – so no warning is echoed.