1

Suppose I have the following json (structured as <String key, Map value>):

{
'A1': {'name': 'a'},
'B2': {'name': 'b'}
}

and I want to parse it to this class (notice that I use the key as the id for that user), using the fromJson factory method, which accepts two arguments:

Class User {
   final String id;
   final String name;

   factory User.fromJson(Map<String, dynamic> json, String key) {
      return User(
         id: key,
         name: json['name'],
      );
   }
}

Can I achieve it using json_serializable ?

user6097845
  • 1,257
  • 1
  • 15
  • 33

1 Answers1

-1

The json Map expected by this factory method is just the values of the top-level JSON object you're parsing.

All you need to do is parse the JSON, extract all keys, then pass the values to the factory method.

Something like this:

import 'dart:convert';

const json = '''
{
"A1": {"name": "a"},
"B2": {"name": "b"}
}
''';

class User {
  final String id;
  final String name;

  User({required this.id, required this.name});

  factory User.fromJson(Map<String, dynamic> json, String key) {
    return User(
      id: key,
      name: json['name'],
    );
  }
  @override
  String toString() => 'User(id=$id, name=$name)';
}

main() {
  final map = jsonDecode(json);
  map.forEach((id, userJson) {
    final user = User.fromJson(userJson, id);
    print(user);
  });
}

Prints:

User(id=A1, name=a)
User(id=B2, name=b)

Now, to use json_serializable, just annotate it and replace your implementation with the generated one...

@JsonSerializable()
class User {
     ...

    factory User.fromJson(Map<String, dynamic> json, String key) =>
       // pass in only the relevant json Map!
       _$UserFromJson(json[key]);
}
Renato
  • 12,940
  • 3
  • 54
  • 85
  • your first code sample makes total sense, but that's the manual way to do it. regarding the last code sample: indeed I want the JsonSerializable to do the parsing, but I don't see how the 'key' value goes to the 'id' field, and the json to the other fields ('name' etc.) – user6097845 Sep 02 '22 at 10:31