Flutter: Using Map with freezed and json_serializable

Viewed 5756

I have a freezed class which looks like this -

@freezed
abstract class User with _$User {
  factory User(
      {@required String uid,
      String firstName,
      String lastName,
      String email,
      Map<String, dynamic> pictures,
      @Default(false) bool isAdmin}) = _User;

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

This class is saved in cloud firestore and I am using this to read it:

User user = User.fromJson(dataFromFirebase);

But I get this error while reading it:

#0      _$_$_UserFromJson (package:my_app/freezed/freezed_classes.g.dart:15:32)
#1      new _$_User.fromJson (package:my_app/freezed/freezed_classes.freezed.dart:68:7)
#2      _$UserFromJson (package:my_app/freezed/freezed_classes.freezed.dart:11:16)
#3      new User.fromJson (package:my_app/freezed/freezed_classes.dart:18:55)
#4      FirestoreService.getUserInfo (package:my_app/services/firestore_service.dart:75:22)
<asynchronous suspension>
#5      FirebaseAuthService.currUserFromUserCollection (package:my_app/services/firebase_auth_service.dart:27:53)
#6      FirebaseAuthService._userFromFirebase (package:my_app/services/firebase_auth_service.dart:17:27)
#7      FirebaseAuthService.signInWithEmailAndPassword (package:my_app/services/firebase_auth_service.dart:47:12)
<asynchronous suspension>
#8      EmailPasswordSignInModel.submit (package:finc<…>

Does anyone know what might be going on here ? I tried using and as types for my Map class (it has a String key and a String value) but still throws the same exception.

2 Answers

I was getting the same error with json_serializable and freezed when I was adding a Map of Item objects to my Client class without type declarations.

Before (when triggering the error)

Notice Map items, with no specific type declarations. This works fine with plain-ole dart.

@freezed
abstract class Client with _$Client {
  const factory Client(
      String id,
      String name,
      int createdDate,
      int updatedDate,
      List<UploadJob> uploadJobs,
      Map items,
      int clientModelVersion) = _Client;

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

After (properly generating)

Notice Map<String, Item> items, declaring the key as a String, and the value as an Item object. It can now generate properly.

@freezed
abstract class Client with _$Client {
  const factory Client(
      String id,
      String name,
      int createdDate,
      int updatedDate,
      List<UploadJob> uploadJobs,
      Map<String, Item> items,
      int clientModelVersion) = _Client;

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

With this change, it was not necessary for me to use a build.yaml file to declare any_map.

Ok, I finally figured this out. Seems like an issue with json_serializable package. I created a new file called build.yaml in the project root with these contents :

targets:
  $default:
    builders:
      json_serializable:
        options:
          # Options configure how source code is generated for every
          # `@JsonSerializable`-annotated class in the package.
          #
          # The default value for each is listed.
          any_map: true
          checked: false
          create_factory: true
          create_to_json: true
          disallow_unrecognized_keys: false
          explicit_to_json: false
          field_rename: none
          ignore_unannotated: false
          include_if_null: true
          nullable: true

All of the values are defaults except for any_map, which is false by default.

According to the documentation

bool anyMap : If true, Map types are not assumed to be Map – which is the default type of Map instances return by JSON decode in dart:convert.

So setting it to true solved my problem !

Related