Converting Firebase Realtime database json response from _InternalLinkedHashMap<Object?, Object?> to Map<String,dynamic>

565

Solution 1

After searching through multiple Stack posts and GitHub issues on Flutter's repository, I came across this magical line which for some odd reason is the only way to get things to work as of right now. The people that proposed this on flutter's repository also mentioned how weird it is but I'm guessing that Firebase's response is not in a valid JSON format (?). For now, if you want something that works, this is probably it:

jsonDecode(jsonEncode(event.snapshot.value)));

Do note that this is probably bad for performance.

Solution 2

I was able to solve it after investigating how the json value returned by Firebase Real-Time Database actually appears in Flutter.

This unhandled type casting error arises because the RTDB does not return a json object that jsonDecode() can parse. jsonDecode can parse the following json string: -

final source = '{"lastUpdatedID": "R7FIlRodwblI4w", "lastUpdateOn": "1647094887285"}';

But RTDB returns the following json string: -

final source = '{lastUpdatedID: R7FIlRodwblI4w, lastUpdateOn: 1647094887285}';

Notice that the double-quotes are missing. This is why jsonDecode throws an error. So, first we need to add the double-quotes.

final jsonString = origin
      .replaceAll(RegExp(r'\s+'), '')   // To remove all white spaces
      .replaceAll(RegExp(r':'), '":"')  // To add double-quotes on both sides of colon
      .replaceAll(RegExp(r','), '","')  // To add double-quotes on both sides of comma
      .replaceAll(RegExp(r'{'), '{"')   // To add double-quotes after every open curly bracket
      .replaceAll(RegExp(r'}'), '"}');  // To add double-quotes before every closing curly bracket

Now we decode the string: -

final decoded = jsonDecode(jsonString);

We also create a Data Model Class: -

class Model {
  const Model({required this.lastUpdatedID, required this.lastUpdateOn});

  /// This factory constructor parses the [lastUpdateOn] as int (if possible)
  factory Model.fromJson(Map<String, dynamic> json) => Model(
        lastUpdatedID: json['lastUpdatedID'] as String,
        lastUpdateOn: int.tryParse(json['lastUpdateOn']) ?? 0,
      );

  Map<String, dynamic> toJson() => {
        'lastUpdatedID': lastUpdatedID,
        'lastUpdateOn': lastUpdateOn,
      };

  final String lastUpdatedID;
  final int lastUpdateOn;

  @override
  String toString() =>
      'Model(lastUpdatedID: $lastUpdatedID, lastUpdateOn: $lastUpdateOn)';
}

Finally, use the fromJson factory constructor to create a model instance: -

final model = Model.fromJson(value);

Here's the complete code: -

import 'dart:convert';

void main() {
  final origin = '{lastUpdatedID: R7FIlRodwblI4w, lastUpdateOn: 1647094887285}';

  final jsonString = origin
      .replaceAll(RegExp(r'\s+'), '')
      .replaceAll(RegExp(r':'), '":"')
      .replaceAll(RegExp(r','), '","')
      .replaceAll(RegExp(r'{'), '{"')
      .replaceAll(RegExp(r'}'), '"}');
  print(jsonString);

  final value = jsonDecode(jsonString);
  print('value.runtimeType : ' + value.runtimeType.toString());
  print('value : ' + value.toString());

  final model = Model.fromJson(value);
  print('model : $model');
}

class Model {
  const Model({required this.lastUpdatedID, required this.lastUpdateOn});

  factory Model.fromJson(Map<String, dynamic> json) => Model(
        lastUpdatedID: json['lastUpdatedID'] as String,
        lastUpdateOn: int.tryParse(json['lastUpdateOn']) ?? 0,
      );

  Map<String, dynamic> toJson() => {
        'lastUpdatedID': lastUpdatedID,
        'lastUpdateOn': lastUpdateOn,
      };

  final String lastUpdatedID;
  final int lastUpdateOn;

  @override
  String toString() =>
      'Model(lastUpdatedID: $lastUpdatedID, lastUpdateOn: $lastUpdateOn)';
}
Share:
565
Stelios Papamichail
Author by

Stelios Papamichail

Computer Science undergrad at the University of Crete &amp; passionate Software developer.

Updated on January 01, 2023

Comments

  • Stelios Papamichail
    Stelios Papamichail over 1 year

    I have a database in my Firebase Realtime database with children that look like this: enter image description here

    Here's the JSON that I receive in my Flutter app from my firebase call:

    {
      "gameAnalytics" : {
        "log" : {
          "20210926073039AbMc4uSXywqpK9OcusSV" : {
            "cityID" : "newYork",
            "countryCode" : "USA",
            "gameID" : "20210927065000Upper90IndnewYofootbiGZYy",
            "gamePaymentMethod" : "payAtPitch",
            "players" : {
              "umZ5ezrtI6a3UoCDWFDc3hInoNA2" : {
                "pnam" : "Mario Rest",
                "url" : "https://i.ibb.co/blahblah.jpg"
              }
            },
            "sportID" : "football",
            "status" : {
              "202109261130395laHd8h77R" : "completing, send back",
              "20210926113039BcUQ8RdbHs" : "payAtPitch",
              "20210926113039Ck9JsD1uf1" : "playersAdded"
            },
            "timeAndDateString" : "20210926073039",
            "totalCost" : 999,
            "type" : "ADD",
            "userWhoAddedID" : "umZ5ezrtI6a3UoCDWFDc3hInoNA2",
            "wantsToBeOrganizer" : true
          },
          "202109261146540focIuCQRi3wNfSluvkl" : {
            "cityID" : "newYork",
            "countryCode" : "USA",
            "gameID" : "20210927065000Upper90IndnewYofootbiGZYy",
            "gamePaymentMethod" : "payByBalance",
            "players" : {
              "hOBQJtqCCNgGBVrAv2MqeaFJmdu1" : {
                "pnam" : "Seong Kang",
                "url" : "messi"
              }
            },
            "promoCodeData" : "U90qaL",
            "sportID" : "football",
            "status" : {
              "2021092615465414NXsxwW51" : "playersAdded",
              "20210926154654A60TLCmS2t" : "paidByBalance",
              "20210926154654VtYR1t4bMZ" : "completing, send back"
            },
            "timeAndDateString" : "20210926114654",
            "totalCost" : 0,
            "type" : "ADD",
            "userWhoAddedID" : "hOBQJtqCCNgGBVrAv2MqeaFJmdu1",
            "wantsToBeOrganizer" : false
          },
          "20210926204533DjF3lMCMDpvwHfsh6lQJ" : {
            "amountToRefund" : 0,
            "promoCodes" : {
              "hOBQJtqCCNgGBVrAv2MqeaFJmdu1" : "U90qaL"
            },
            "status" : {
              "20210927004533ZWGNEMX27V" : "REFUNDING: 0  null  hOBQJtqCCNgGBVrAv2MqeaFJmdu1"
            },
            "type" : "CANCEL",
            "userWhoAddedID" : "hOBQJtqCCNgGBVrAv2MqeaFJmdu1"
          }
        },
        "pitchCost" : 3500,
        "playerNumbers" : {
          "hoursBefore12" : 2,
          "hoursBefore24" : 1,
          "hoursBefore3" : 2,
          "hoursBefore36" : 1,
          "hoursBefore48" : 1,
          "hoursBefore6" : 2,
          "hoursBefore72" : 1,
          "hoursBefore96" : 1
        },
        "timings" : {
          "added" : {
            "20210917004938" : "organiserID12345",
            "20210926113040" : "umZ5ezrtI6a3UoCDWFDc3hInoNA2",
            "20210926154656" : "hOBQJtqCCNgGBVrAv2MqeaFJmdu1"
          },
          "cancelled" : {
            "20210917004939" : "playersUnCancelled",
            "20210927004522" : "playersCancelled"
          },
          "removed" : {
            "20210926113042" : "organiserID12345"
          }
        }
      },
      "gameData" : {
        "addFakePlayers" : false,
        "can" : true,
        "canAddPromoCode" : true,
        "canDes" : {
          "en" : "somedesc"
        },
        "canMes" : "blahblah.",
        "cost" : 999,
        "cur" : 2,
        "currency" : "usd",
        "dat" : "20210927065000",
        "descriptions" : {
          "en" : "blahblah"
        },
        "dur" : "60 minutes",
        "expOrg" : "",
        "gameTypes" : {
          "en" : "blahblah"
        },
        "hostConfirmed" : false,
        "hostInfo" : {
          "hostDescription" : "blahblah",
          "hostNickname" : "Mario R",
          "hostPhoto" : "https://i.ibb.co/blahblah.jpg",
          "isSuperHost" : false
        },
        "lid" : "Upper90IndoorQueensabcde739219515176663407563157034467ap0mr",
        "max" : 15,
        "mes" : "blahblah",
        "mes1" : "my disappointment",
        "mes2" : "is immessurable",
        "mes3" : "and my day",
        "payAtPitchMessage" : {
          "en" : "is ruined"
        },
        "paymentType" : "justOnline",
        "paymentsAllowed" : [ "card" ],
        "pla1" : {
          "hOBQJtqCCNgGBVrAv2MqeaFJmdu1" : {
            "pnam" : "blahblah",
            "url" : "messi"
          }
        },
        "pla2" : {
          "umZ5ezrtI6a3UoCDWFDc3hInoNA2" : {
            "organizer" : true,
            "pnam" : "Mario Rest",
            "url" : "https://i.ibb.co/blahblah.jpg"
          }
        },
        "pub" : false,
        "removalAllowed" : true,
        "showHostConfirmButton" : false,
        "spotEn" : true,
        "surl" : "https://someurl",
        "title" : {
          "en" : "ok"
        }
      },
      "mess" : {
        "-MjlDj5szZxKaDs0p3CN" : {
          "mes" : "ok",
          "tim" : "20210916204938",
          "unm" : "blahblah",
          "usi" : "XwyPhbjzeKNYVczPdCPFTG0DZbj1"
        },
        "-MjlDj6bnMvKUO76EjLE" : {
          "mes" : "ok",
          "tim" : "20210916204938",
          "unm" : "blahblah",
          "usi" : "XwyPhbjzeKNYVczPdCPFTG0DZbj1"
        },
        "-MjlDj7SeqRV0KzRzFFX" : {
          "mes" : "ok",
          "tim" : "20210916204939",
          "unm" : "bllblb",
          "usi" : "XwyPhbjzeKNYVczPdCPFTG0DZbj1"
        },
        "-MjlDj8C-p406IK8I-cb" : {
          "mes" : "msg",
          "tim" : "20210916204940",
          "unm" : "msg",
          "usi" : "XwyPhbjzeKNYVczPdCPFTG0DZbj1"
        }
      },
      "payment" : {
        "playerPaymentStatus" : {
          "hOBQJtqCCNgGBVrAv2MqeaFJmdu1" : {
            "date" : "20210927004533",
            "refundedAmount" : 0,
            "stripePaymentNotConfirmed" : true,
            "type" : "notPaidForGame",
            "userWhoAddedID" : "hOBQJtqCCNgGBVrAv2MqeaFJmdu1"
          }
        }
      },
      "userReview" : {
        "showReview" : true
      }
    }
    

    I'm trying to create a Map<String, dynamic> from this response by using Map<String,dynamic>.from() as seen below:

    class PickUpGameItem extends StatefulWidget {
      final String gameId;
    
      const PickUpGameItem(this.gameId, [Key? key]) : super(key: key);
    
      @override
      _PickUpGameItemState createState() => _PickUpGameItemState();
    }
    
    class _PickUpGameItemState extends State<PickUpGameItem> {
      late StreamSubscription _pickUpGameDetailsStreamSub;
      PickUpGameDetails? gameDetails;
    
      @override
      void initState() {
        super.initState();
        _setListeners();
      }
    
      @override
      void deactivate() {
        _pickUpGameDetailsStreamSub.cancel();
        super.deactivate();
      }
    
      void _setListeners() {
        _pickUpGameDetailsStreamSub = FirebaseDatabase()
            .reference()
            .child(
                '.../gamesDetailed/${widget.gameId}/')
            .onValue
            .listen((event) {
          final detailsJson = Map<String, dynamic>.from(event.snapshot.value);
          setState(() {
            gameDetails = PickUpGameDetails.fromJson(detailsJson);
            print(gameDetails.toString());
          });
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Container(
          padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20),
          child: Row(
            children: [
              ClipRRect(
                borderRadius: BorderRadius.circular(8.0),
                child: const Image(
                  fit: BoxFit.fill,
                  width: 80.0,
                  height: 80.0,
                  image: AssetImage('assets/images/temp_city_img.jpg'),
                ),
              ),
              const SizedBox(
                width: 10,
              ),
              Expanded(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: const [
                    Text(
                      'Lorem ipsum dolor sit amet this is a test ......................................',
                      style: TextStyle(
                          color: Colors.black,
                          fontWeight: FontWeight.bold,
                          fontSize: 16),
                      maxLines: 1,
                      overflow: TextOverflow.ellipsis,
                    ),
                    SizedBox(
                      height: 10,
                    ),
                    Text(
                      'Lorem ipsum dolor sit amet this is a test ......................................',
                      style: TextStyle(
                          color: Colors.grey,
                          fontWeight: FontWeight.normal,
                          fontSize: 14),
                      maxLines: 1,
                      overflow: TextOverflow.ellipsis,
                    ),
                  ],
                ),
              ),
              const SizedBox(
                width: 10,
              ),
              Flexible(
                flex: 0,
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    const Text(
                      'Football',
                      style: TextStyle(
                          color: Colors.black,
                          fontWeight: FontWeight.bold,
                          fontSize: 16),
                    ),
                    const SizedBox(
                      height: 10,
                    ),
                    Row(
                      children: const [
                        Text(
                          '14/16',
                          style: TextStyle(
                              color: Colors.grey,
                              fontWeight: FontWeight.normal,
                              fontSize: 14),
                        ),
                        SizedBox(
                          width: 5,
                        ),
                        Icon(Icons.ac_unit)
                      ],
                    ),
                  ],
                ),
              ),
            ],
          ),
        );
      }
    }
    

    When I run the app, I get an error saying that the internal linked hash map isn't a subtype of map and that the error occurs when calling GameAnalytics.fromJson(). I've seen multiple similar posts but their error mentioned an _InternalLinkedHashMap<String?, dynamic> map. Why Is this linked hash map in my response using Object? for both keys and values?

    [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: type '_InternalLinkedHashMap<Object?, Object?>' is not a subtype of type 'Map<String, dynamic>'
    

    Here are my dart model classes:

    PickUpGameDetails.dart:

    class PickUpGameDetails {
      GameAnalytics? gameAnalytics;
      GameData? gameData;
      UserReview? userReview;
    
      PickUpGameDetails(
          {required this.gameAnalytics,
          required this.gameData,
          required this.userReview});
    
      PickUpGameDetails.fromJson(Map<String, dynamic> json) {
        gameAnalytics = json['gameAnalytics'] != null
            ? GameAnalytics.fromJson(json['gameAnalytics'])
            : null;
        gameData =
            json['gameData'] != null ? GameData.fromJson(json['gameData']) : null;
        userReview = json['userReview'] != null
            ? UserReview.fromJson(json['userReview'])
            : null;
      }
    
      Map<String, dynamic> toJson() {
        final Map<String, dynamic> data = new Map<String, dynamic>();
        if (gameAnalytics != null) {
          data['gameAnalytics'] = gameAnalytics!.toJson();
        }
        if (gameData != null) {
          data['gameData'] = gameData!.toJson();
        }
        if (userReview != null) {
          data['userReview'] = userReview!.toJson();
        }
        return data;
      }
    }
    

    GameAnalytics.dart:

    class GameAnalytics {
      late int pitchCost;
      PlayerNumbers? playerNumbers;
      Timings? timings;
    
      GameAnalytics(
          {required this.pitchCost,
          required this.playerNumbers,
          required this.timings});
    
      GameAnalytics.fromJson(Map<String, dynamic> json) {
        pitchCost = json['pitchCost'];
        playerNumbers = json['playerNumbers'] != null
            ? PlayerNumbers.fromJson(json['playerNumbers'])
            : null;
        timings =
            json['timings'] != null ? Timings.fromJson(json['timings']) : null;
      }
    
      Map<String, dynamic> toJson() {
        final Map<String, dynamic> data = <String, dynamic>{};
        data['pitchCost'] = pitchCost;
        if (playerNumbers != null) {
          data['playerNumbers'] = playerNumbers!.toJson();
        }
        if (timings != null) {
          data['timings'] = timings!.toJson();
        }
        return data;
      }
    }
    

    PlayerNumbers.dart:

    class PlayerNumbers {
      late int hoursBefore12;
      late int hoursBefore24;
      late int hoursBefore3;
      late int hoursBefore36;
      late int hoursBefore48;
      late int hoursBefore6;
      late int hoursBefore72;
      late int hoursBefore96;
    
      PlayerNumbers(
          {required this.hoursBefore12,
          required this.hoursBefore24,
          required this.hoursBefore3,
          required this.hoursBefore36,
          required this.hoursBefore48,
          required this.hoursBefore6,
          required this.hoursBefore72,
          required this.hoursBefore96});
    
      PlayerNumbers.fromJson(Map<String, dynamic> json) {
        hoursBefore12 = json['hoursBefore12'];
        hoursBefore24 = json['hoursBefore24'];
        hoursBefore3 = json['hoursBefore3'];
        hoursBefore36 = json['hoursBefore36'];
        hoursBefore48 = json['hoursBefore48'];
        hoursBefore6 = json['hoursBefore6'];
        hoursBefore72 = json['hoursBefore72'];
        hoursBefore96 = json['hoursBefore96'];
      }
    
      Map<String, dynamic> toJson() {
        final Map<String, dynamic> data = <String, dynamic>{};
        data['hoursBefore12'] = hoursBefore12;
        data['hoursBefore24'] = hoursBefore24;
        data['hoursBefore3'] = hoursBefore3;
        data['hoursBefore36'] = hoursBefore36;
        data['hoursBefore48'] = hoursBefore48;
        data['hoursBefore6'] = hoursBefore6;
        data['hoursBefore72'] = hoursBefore72;
        data['hoursBefore96'] = hoursBefore96;
        return data;
      }
    }
    

    Timings.dart:

    class Timings {
      Map<String, dynamic>? added;
      Map<String, dynamic>? cancelled;
      Map<String, dynamic>? removed;
    
      Timings(
          {required this.added, required this.cancelled, required this.removed});
    
      Timings.fromJson(Map<String, dynamic> json) {
        added = json['added'];
        cancelled = json['cancelled'];
      }
    
      Map<String, dynamic> toJson() {
        final Map<String, dynamic> data = <String, dynamic>{};
        if (added != null) {
          data['added'] = added;
        }
        if (cancelled != null) {
          data['cancelled'] = cancelled;
        }
        if (removed != null) {
          data['removed'] = removed;
        }
        return data;
      }
    }
    

    UserReview.dart:

    class UserReview {
      bool? showReview;
    
      UserReview({required this.showReview});
    
      UserReview.fromJson(Map<String, dynamic> json) {
        showReview = json['showReview'];
      }
    
      Map<String, dynamic> toJson() {
        final Map<String, dynamic> data = <String, dynamic>{};
        data['showReview'] = showReview;
        return data;
      }
    }
    

    GameData.dart:

    class GameData {
      late bool addFakePlayers;
      late bool hasBeenCancelled;
      late bool canAddPromoCode;
      late String cancellationDescription;
      late String cancellationMsg;
      late int cost;
      late int cur;
      late String currency;
      late String dateTime;
      late String description;
      late String durationMsg;
      late String expOrg;
      late String gameTypeMsg;
      late bool hostConfirmed;
      late String lid;
      late int maxPlayers;
      late List<String> messages;
      late String payAtPitchMessage;
      late String paymentType;
      late List<String> paymentsAllowed;
      Team? team1;
      Team? team2;
      late bool pub;
      late bool removalAllowed;
      late bool showHostConfirmButton;
      late bool spotEn;
      late String surl;
      late String title;
    
      GameData(
          {required this.addFakePlayers,
          required this.hasBeenCancelled,
          required this.canAddPromoCode,
          required this.cancellationDescription,
          required this.cancellationMsg,
          required this.cost,
          required this.cur,
          required this.currency,
          required this.dateTime,
          required this.description,
          required this.durationMsg,
          required this.expOrg,
          required this.gameTypeMsg,
          required this.hostConfirmed,
          required this.lid,
          required this.maxPlayers,
          required this.messages,
          required this.payAtPitchMessage,
          required this.paymentType,
          required this.paymentsAllowed,
          required this.team1,
          required this.team2,
          required this.pub,
          required this.removalAllowed,
          required this.showHostConfirmButton,
          required this.spotEn,
          required this.surl,
          required this.title});
    
      GameData.fromJson(Map<String, dynamic> json) {
        addFakePlayers = json['addFakePlayers'];
        hasBeenCancelled = json['can'];
        canAddPromoCode = json['canAddPromoCode'];
        cancellationDescription = json['canDes']['en'];
        cancellationMsg = json['canMes'];
        cost = json['cost'];
        cur = json['cur'];
        currency = json['currency'];
        dateTime = json['dat'];
        description = json['descriptions']['en'];
        durationMsg = json['dur'];
        expOrg = json['expOrg'];
        gameTypeMsg = json['gameTypes']['en'];
        hostConfirmed = json['hostConfirmed'];
        lid = json['lid'];
        maxPlayers = json['max'];
        messages.add(json['mes']);
        messages.add(json['mes1']);
        messages.add(json['mes2']);
        messages.add(json['mes3']);
        payAtPitchMessage = json['payAtPitchMessage']['en'];
        paymentType = json['paymentType'];
        paymentsAllowed = json['paymentsAllowed'].cast<String>();
        team1 = json['pla1'] != null ? Team.fromJson(json['pla1']) : null;
        team2 = json['pla2'] != null ? Team.fromJson(json['pla2']) : null;
        pub = json['pub'];
        removalAllowed = json['removalAllowed'];
        showHostConfirmButton = json['showHostConfirmButton'];
        spotEn = json['spotEn'];
        surl = json['surl'];
        title = json['title']['en'];
      }
    
      Map<String, dynamic> toJson() {
        final Map<String, dynamic> data = <String, dynamic>{};
        data['addFakePlayers'] = addFakePlayers;
        data['can'] = hasBeenCancelled;
        data['canAddPromoCode'] = canAddPromoCode;
        data['canDes'] = cancellationDescription;
        data['canMes'] = cancellationMsg;
        data['cost'] = cost;
        data['cur'] = cur;
        data['currency'] = currency;
        data['dat'] = dateTime;
        data['descriptions'] = description;
        data['dur'] = durationMsg;
        data['expOrg'] = expOrg;
        data['gameTypes'] = gameTypeMsg;
        data['hostConfirmed'] = hostConfirmed;
        data['lid'] = lid;
        data['max'] = maxPlayers;
        data['mes'] = messages.elementAt(0);
        data['mes1'] = messages.elementAt(1);
        data['mes2'] = messages.elementAt(2);
        data['mes3'] = messages.elementAt(3);
        data['payAtPitchMessage'] = payAtPitchMessage;
        data['paymentType'] = paymentType;
        data['paymentsAllowed'] = paymentsAllowed;
        data['pla1'] = team1?.toJson();
        data['pla2'] = team2?.toJson();
        data['pub'] = pub;
        data['removalAllowed'] = removalAllowed;
        data['showHostConfirmButton'] = showHostConfirmButton;
        data['spotEn'] = spotEn;
        data['surl'] = surl;
        data['title'] = title;
        return data;
      }
    }
    

    Team.dart:

    class Team {
      Map<String, Player> players;
    
      Team({required this.players});
    
      factory Team.fromJson(Map<String, dynamic> json) {
        Map<String, Player> _players = {};
        for (String key in json.keys) {
          _players[key] = Player.fromJson(json[key]);
        }
        return Team(players: _players);
      }
    
      Map<String, dynamic> toJson() {
        Map<String, dynamic> json = <String, dynamic>{};
        for (String key in players.keys) {
          json[key] = players[key];
        }
        return json;
      }
    }
    

    Player.dart:

    class Player {
      String name;
      String url;
    
      Player({required this.name, required this.url});
    
      factory Player.fromJson(Map<String, dynamic> json) {
        return Player(name: json['pname'], url: json['url']);
      }
    
      Map<String, dynamic> toJson() {
        final json = <String, dynamic>{};
        json['pname'] = name;
        json['url'] = url;
        return json;
      }
    }
    
    • Luke Irvin
      Luke Irvin over 2 years
      Hello, I am stuck on the exact same thing. Have you found the preferred solution?
  • Stelios Papamichail
    Stelios Papamichail over 2 years
    Hi and thank you for the very thorough answer. It's very informative. I decided to go with the factory approach since in the future I'll be making use of the different values of gameTypes, etc. However, this doesn't seem to affect the original issue and the casting error stills persists.
  • Luke Irvin
    Luke Irvin over 2 years
    Hi Luan, I am using the above, and I have tried the proposed solution below, but I still get the same Unhandled Exception. Any other suggestions?
  • Alan Dsilva
    Alan Dsilva about 2 years
    Is there a bettter way to solve this????. Map.from() or as Map<> doesn't work.