Ad

Parsing JSON With A Nested, Dynamic Type

- 1 answer

Let's assume I have 3 data classes (which in reality may be many more). Class Aor class B shall be wrapped in class Wrap with a data type identifier. This shall allow using the same process inside the app for any data type provided by the json interface.

class Wrap{
  int id;
  List<dynamic> dataSet;
  Wrap({required this.id, required this.dataSet});
}

class A{
  int a=0;
  A({this.a});
}

class B{
  bool b=true;
  B({this.b});
}

My aim was to use a map getDataType = {0: A, 1: B}; and then to parse the nested Json with

dataSets: List<dynamic>.from(json["dataSets"].map((d) => getDataType[json["id"].fromJson(d)).toList();

But unfortunately this already fails when trying to access a class method from the variable containing the type

class A{
  int i=0; A({i});
  factory A.test(int i) => A(2*i); 
}

main() {
  final t = A;
  final x = t.test(2);
}

Anyone with a smart idea how to achieve this?

The rational behind this unorthodox data structure is: I have a data manager in the business logic layer that triggers different UIs depending on some events, coming from a different logic. The manager then fetches the specific data for the UI. To streamline this, the same repository with the same functions shall be used. However, the repository function uses a different database table depending on the UI.

UPDATE: Most basic example json:

{
 "id": 0,
  "data": [ 
    {
      "problemId": 0,
      "level": 2
    }
  ]
}
Ad

Answer

First of all create an abstact class for datasets

abstract class Dataset {
  const Dataset();
  factory Dataset.fromMap(Map<String, dynamic> map, int type) {
    switch (type) {
      case 0:
        return ADataset.fromMap(map);
      case 1:
        return BDataset.fromMap(map);
      default:
        throw Exception("Class with id $type couldn't be found");
    }
  }
}

and replace List<dynamic> dataSet; in Wrap class with List<Dataset> dataSet;

Now you can simply create dataset classes by extending this Dataset class

class ADataset extends Dataset {
  final int fieldA;
  ADataset(
    this.fieldA,
  );
  factory ADataset.fromMap(Map<String, dynamic> map) {
    return ADataset(map['int field']);
  }
}

class BDataset extends Dataset {
  final String fieldB;
  BDataset(
    this.fieldB,
  );
  factory BDataset.fromMap(Map<String, dynamic> map) {
    return BDataset(map['string field']);
  }
}

So now all you need to do is

dataSets: List<Dataset>.from(map['datasets'].map(
    (dataset) => Dataset.fromMap(dataset, map['type']),
  ));
Ad
source: stackoverflow.com
Ad