I am trying to learn flutter but I am stuck at JSON serialization. I was following some tutorials in YouTube and from the flutter docs, but I am having a bit of hard time with the Serialization. Could you please help me a little bit, this is for educational purpose, so I am more interested in the theory behind rather than a solution in itself, however even with only the solution I think I can try to understand the process. I should mention that I am aware of this, but in my case I have nested objects in the data and that is confusing me.

Sample of response data, it is basically a shop that for each day they have a list of days when they are opened, and for each object (day) they have the open time and date.

{
    "data": [
        {
            "openTime": {
                "open": "10:00",
                "close": "20:00"
            },
            "date": {
                "gregorian": {
                    "day": "01",
                    "weekday": {
                        "en": "Friday",
                        "de": "Freitag"
                    },
                    "month": {
                        "number": 5,
                        "en": "May",
                        "de": "Mai"
                    },
                    "year": "2020"
                }
            }
        },
        {
            "openTime": {
                "open": "12:00",
                "close": "18:00"
            },
            "date": {
                "gregorian": {
                    "day": "02",
                    "weekday": {
                        "en": "Saturday",
                        "de": "Samstag"
                    },
                    "month": {
                        "number": 5,
                        "en": "May",
                        "de": "Mai"
                    },
                    "year": "2020"
                }
            }
        }
    ]
}

My function that fetch the data:

Future<Mall> fetchData() async {
  final response = await http.get(url);
  if (response.statusCode == 200) {
    return Mall.fromJson(json.decode(response.body));
  } else {
    throw Exception('Failed to load data!');
  }
}

The class Mall in my case has the openTime and date, which I think where my problem is.

class Mall {
  final dynamic openTime;
  final dynamic date;

  Mall({this.openTime, this.date});

  factory Mall.fromJson(Map<String, dynamic> json) {
    return Mall(openTime: json['openTime'], date: json['date']);
  }
}

The result that I am trying to produce should be look something like this so I can iterate through the list of the data and built a card for a number of days (e.g last 7 days)

var time = [
  {
    "openTime": {"open": "10:00", "close": "20:00"},
    "date": "01 May 2020"
  },
  {
    "openTime": {"open": "12:00", "close": "18:00"},
    "date": "02 May 2020"
  },
];

The error that I get is:

type 'List<dynamic>' is not a subtype of type 'Map<String, dynamic>'

Please let me know if you need further details. Thanks in advance.


Solution 1: Bassem Abd Allah

you have some errors in your code.

1- in this part your response is object in container object called "data"

Future<Mall> fetchData() async {
  final response = await http.get(url);
  if (response.statusCode == 200) {
    return Mall.fromJson(json.decode(response.body));  //here
  } else {
    throw Exception('Failed to load data!');
  }
}

2- your mall data is a nested object in 'data' so customize your mall class to be

class Mall {
    List<Datum> data;

    Mall({
        this.data,
    });

    factory Mall.fromJson(Map<String, dynamic> json) => Mall(
        data: List<Datum>.from(json["data"].map((x) => Datum.fromJson(x))),
    );

    Map<String, dynamic> toJson() => {
        "data": List<dynamic>.from(data.map((x) => x.toJson())),
    };
}

class Datum {
    OpenTime openTime;
    Date date;

    Datum({
        this.openTime,
        this.date,
    });

    factory Datum.fromJson(Map<String, dynamic> json) => Datum(
        openTime: OpenTime.fromJson(json["openTime"]),
        date: Date.fromJson(json["date"]),
    );

    Map<String, dynamic> toJson() => {
        "openTime": openTime.toJson(),
        "date": date.toJson(),
    };
}

class Date {
    Gregorian gregorian;

    Date({
        this.gregorian,
    });

    factory Date.fromJson(Map<String, dynamic> json) => Date(
        gregorian: Gregorian.fromJson(json["gregorian"]),
    );

    Map<String, dynamic> toJson() => {
        "gregorian": gregorian.toJson(),
    };
}

class Gregorian {
    String day;
    Weekday weekday;
    Month month;
    String year;

    Gregorian({
        this.day,
        this.weekday,
        this.month,
        this.year,
    });

    factory Gregorian.fromJson(Map<String, dynamic> json) => Gregorian(
        day: json["day"],
        weekday: Weekday.fromJson(json["weekday"]),
        month: Month.fromJson(json["month"]),
        year: json["year"],
    );

    Map<String, dynamic> toJson() => {
        "day": day,
        "weekday": weekday.toJson(),
        "month": month.toJson(),
        "year": year,
    };
}

class Month {
    int number;
    String en;
    String de;

    Month({
        this.number,
        this.en,
        this.de,
    });

    factory Month.fromJson(Map<String, dynamic> json) => Month(
        number: json["number"],
        en: json["en"],
        de: json["de"],
    );

    Map<String, dynamic> toJson() => {
        "number": number,
        "en": en,
        "de": de,
    };
}

class Weekday {
    String en;
    String de;

    Weekday({
        this.en,
        this.de,
    });

    factory Weekday.fromJson(Map<String, dynamic> json) => Weekday(
        en: json["en"],
        de: json["de"],
    );

    Map<String, dynamic> toJson() => {
        "en": en,
        "de": de,
    };
}

class OpenTime {
    String open;
    String close;

    OpenTime({
        this.open,
        this.close,
    });

    factory OpenTime.fromJson(Map<String, dynamic> json) => OpenTime(
        open: json["open"],
        close: json["close"],
    );

    Map<String, dynamic> toJson() => {
        "open": open,
        "close": close,
    };
}

now you can fecch mall data as you did

Future<Mall> fetchData() async {
  final response = await http.get(url);
  if (response.statusCode == 200) {
    return Mall.fromJson(json.decode(response.body));  //here
  } else {
    throw Exception('Failed to load data!');
  }
}