Mobx.dart: type 'List<dynamic>' is not a subtype of type 'List<Map<String, dynamic>>' in type cast

Created on 25 Sep 2019  路  5Comments  路  Source: mobxjs/mobx.dart

=========parkings.dart ===============

@JsonSerializable()
class Parkings extends _Parkings with _$Parkings {
  static Parkings fromJson(Map<String, dynamic> json) =>
      _$ParkingsFromJson(json);
  static Map<String, dynamic> toJson(Parkings parkings) =>
      _$ParkingsToJson(parkings);
}

abstract class _Parkings with Store {
  @observable
  @_ObservableListJsonConverter()
  ObservableList<Parking> parkings = ObservableList<Parking>();
  }
}

class _ObservableListJsonConverter
    implements
        JsonConverter<ObservableList<Parking>, List<Map<String, dynamic>>> {
  const _ObservableListJsonConverter();

  @override
  ObservableList<Parking> fromJson(List<Map<String, dynamic>> json) =>
      ObservableList.of(json.map(Parking.fromJson));

  @override
  List<Map<String, dynamic>> toJson(ObservableList<Parking> list) =>
      list.map(Parking.toJson).toList();
}

================parking.dart===================

@JsonSerializable()
class Parking extends _Parking with _$Parking {
  Parking({
    int id,
    bool isAvailable,
    String price,
    List<double> coordinates,
  }) : super(id, isAvailable, price, coordinates);

  static Parking fromJson(Map<String, dynamic> json) => _$ParkingFromJson(json);
  static Map<String, dynamic> toJson(Parking todo) => _$ParkingToJson(todo);
}

abstract class _Parking with Store {
  _Parking(
    this.id,
    this.isAvailable,
    this.price,
    this.coordinates,
  );

  int id;
  bool isAvailable;
  String price;
  List<double> coordinates;
}

================Json response ============

{
    "parkings": [
        {
            "id": 4,
            "isAvailable": false,
            "price": "\\509",
            "coordinates": [
                37.5211120602382,
                127.170693146119
            ]
        },
        ...
   ]
}

===================================
final jsonResponse = jsonDecode(response.body);
final Parkings parkingList = Parkings.fromJson(jsonResponse); => Error! (type 'List' is not a subtype of type 'List>' in type cast)

I want to figure it out because using json_serializable together with mobx is much better i think. I have no idea why this happens.

Most helpful comment

I had some similar problems, and I want to caveat that I am by no means an expert. But here is my suggestion (and if anyone knows better I would love to be corrected here).

First the code I suggest:

abstract class _Parkings with Store {
  @observable
  @_ObservableListJsonConverter()
  ObservableList<Parking> parkings = ObservableList<Parking>();
}

class _ObservableListJsonConverter
    implements
        JsonConverter<ObservableList<Parking>, List<dynamic>> {
  const _ObservableListJsonConverter();

  @override
  ObservableList<Parking> fromJson(List<dynamic> json) =>
      ObservableList.of(json.cast<Map<String, dynamic>>().map(Parking.fromJson));

  @override
  List<Map<String, dynamic>> toJson(ObservableList<Parking> list) =>
      list.map(Parking.toJson).toList();
}

And some (probably unsatisfying) explanation of the changes:

  1. I think you need to add a type to the ObservableList, which I've done in the code.
  2. In my application, I for some reason changed the json parameter to be List<dynamic>. I think it was to handle empty lists, in which case dart complained that List<dynamic> was not a subtype of List<Map<String, dynamic>>, but I can't remember for sure. So your mileage may vary.
  3. Having changed json to List<dynamic>, I need to cast it so I can feed it to fromJson. So I use json.cast<Map<String,dynamic>>() in the fromJson function.

If that code looks like it's a mess, I definitely don't disagree. I'm a rubyist by trade and I have a serious love/hate thing going with Dart's type system (or maybe any type system?). So if some other reader comes across this and I'm making it too complicated please let me know!

But hopefully it's enough to get you back on track at least. Also, for future reference, you can create codeblocks by starting a section with three back-ticks (```) and then closing it with three more. Even better, you can specify the language in the opening (```dart).

All 5 comments

I had some similar problems, and I want to caveat that I am by no means an expert. But here is my suggestion (and if anyone knows better I would love to be corrected here).

First the code I suggest:

abstract class _Parkings with Store {
  @observable
  @_ObservableListJsonConverter()
  ObservableList<Parking> parkings = ObservableList<Parking>();
}

class _ObservableListJsonConverter
    implements
        JsonConverter<ObservableList<Parking>, List<dynamic>> {
  const _ObservableListJsonConverter();

  @override
  ObservableList<Parking> fromJson(List<dynamic> json) =>
      ObservableList.of(json.cast<Map<String, dynamic>>().map(Parking.fromJson));

  @override
  List<Map<String, dynamic>> toJson(ObservableList<Parking> list) =>
      list.map(Parking.toJson).toList();
}

And some (probably unsatisfying) explanation of the changes:

  1. I think you need to add a type to the ObservableList, which I've done in the code.
  2. In my application, I for some reason changed the json parameter to be List<dynamic>. I think it was to handle empty lists, in which case dart complained that List<dynamic> was not a subtype of List<Map<String, dynamic>>, but I can't remember for sure. So your mileage may vary.
  3. Having changed json to List<dynamic>, I need to cast it so I can feed it to fromJson. So I use json.cast<Map<String,dynamic>>() in the fromJson function.

If that code looks like it's a mess, I definitely don't disagree. I'm a rubyist by trade and I have a serious love/hate thing going with Dart's type system (or maybe any type system?). So if some other reader comes across this and I'm making it too complicated please let me know!

But hopefully it's enough to get you back on track at least. Also, for future reference, you can create codeblocks by starting a section with three back-ticks (```) and then closing it with three more. Even better, you can specify the language in the opening (```dart).

Thank you so much, hmayer00. Now it works!! You are very nice man.

Do i have to make _ObservableListJsonConverter for other mobx store each time?

@Feelthewind Actually I should have mentioned before, I think you want this to be ObservableListParkingConverter, not ObservableListJsonConverter. And then yes, as far as I know you need one for each type that you are converting, in each store in which you are converting it.

Was this page helpful?
0 / 5 - 0 ratings