Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
2.4k views
in Technique[技术] by (71.8m points)

json - Type List<dynamic> is not a subtype of type Map<String dynamic>

I'm pretty new to Flutter programming, and I'm trying to import a local JSON file that contains book data, like title, author, release year etc.

Initially I used a JSON to DART converter to assemble a book data model and I'm now trying to make a getBooksAll() function, in which the program gets the local JSON file and uses the fromJson() method from the BookData class to parse the data to a Map.

The issue I'm getting is that json.decode(value) returns a type List<dynamic> and the fromJson() method takes in a type Map<String, dynamic>. How would I go about fixing this?

Here is the getBooksAll() code:

  static getBooksAll() {
    var booksJson = rootBundle.loadString('assets/bookData.json');
    booksJson.then((value) => BookData.fromJson(json.decode(value)));
  }

Here is the error I'm getting:

E/flutter (10608): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: type 'List<dynamic>' is not a subtype of type 'Map<String, dynamic>'
E/flutter (10608): #0      BookData.getBooksAll.<anonymous closure> (package:well_red_v1/models/book_data_model.dart:56:54)
E/flutter (10608): #1      _rootRunUnary (dart:async/zone.dart:1436:47)
E/flutter (10608): #2      _CustomZone.runUnary (dart:async/zone.dart:1335:19)
E/flutter (10608): <asynchronous suspension>
E/flutter (10608): 

Here is the entire book data model code:

import 'dart:convert';
import 'package:flutter/services.dart';
import 'package:flutter/services.dart' show rootBundle;

class BookData {
  Id? id;
  String? title;
  String? isbn;
  int? pageCount;
  PublishedDate? publishedDate;
  String? thumbnailUrl;
  String? shortDescription;
  String? longDescription;
  String? status;
  List<dynamic>? authors;
  List<dynamic>? categories;

  BookData({this.id, this.title, this.isbn, this.pageCount, this.publishedDate, this.thumbnailUrl, this.shortDescription, this.longDescription, this.status, this.authors, this.categories});

  BookData.fromJson(Map<String, dynamic> json) {
    this.id = json["_id"] == null ? null : Id.fromJson(json["_id"]);
    this.title = json["title"];
    this.isbn = json["isbn"];
    this.pageCount = json["pageCount"];
    this.publishedDate = json["publishedDate"] == null ? null : PublishedDate.fromJson(json["publishedDate"]);
    this.thumbnailUrl = json["thumbnailUrl"];
    this.shortDescription = json["shortDescription"];
    this.longDescription = json["longDescription"];
    this.status = json["status"];
    this.authors = json["authors"] ?? [];
    this.categories = json["categories"] ?? [];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    if(this.id != null)
      data["_id"] = this.id?.toJson();
    data["title"] = this.title;
    data["isbn"] = this.isbn;
    data["pageCount"] = this.pageCount;
    if(this.publishedDate != null)
      data["publishedDate"] = this.publishedDate?.toJson();
    data["thumbnailUrl"] = this.thumbnailUrl;
    data["shortDescription"] = this.shortDescription;
    data["longDescription"] = this.longDescription;
    data["status"] = this.status;
    if(this.authors != null)
      data["authors"] = this.authors;
    if(this.categories != null)
      data["categories"] = this.categories;
    return data;
  }

  static getBooksAll() {
    var booksJson = rootBundle.loadString('assets/bookData.json');
    booksJson.then((value) => BookData.fromJson(json.decode(value)));
  }
}

class PublishedDate {
  String? $date;

  PublishedDate({this.$date});

  PublishedDate.fromJson(Map<String, dynamic> json) {
    this.$date = json["${$date}"];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data["${$date}"] = this.$date;
    return data;
  }
}

class Id {
  String? $oid;

  Id({this.$oid});

  Id.fromJson(Map<String, dynamic> json) {
    this.$oid = json["${$oid}"];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data["${$oid}"] = this.$oid;
    return data;
  }
}

Here is a part of the JSON file:

[
  {
    "_id": 1,
    "title": "Unlocking Android",
    "isbn": "1933988673",
    "pageCount": 416,
    "publishedDate": {
      "$date": "2009-04-01T00:00:00.000-0700"
    },
    "thumbnailUrl": "https://s3.amazonaws.com/AKIAJC5RLADLUMVRPFDQ.book-thumb-images/ableson.jpg",
    "shortDescription": "Unlocking Android: A Developer's Guide provides concise, hands-on instruction for the Android operating system and development tools. This book teaches important architectural concepts in a straightforward writing style and builds on this with practical and useful examples throughout.",
    "longDescription": "Android is an open source mobile phone platform based on the Linux operating system and developed by the Open Handset Alliance, a consortium of over 30 hardware, software and telecom companies that focus on open standards for mobile devices. Led by search giant, Google, Android is designed to deliver a better and more open and cost effective mobile experience.    Unlocking Android: A Developer's Guide provides concise, hands-on instruction for the Android operating system and development tools. This book teaches important architectural concepts in a straightforward writing style and builds on this with practical and useful examples throughout. Based on his mobile development experience and his deep knowledge of the arcane Android technical documentation, the author conveys the know-how you need to develop practical applications that build upon or replace any of Androids features, however small.    Unlocking Android: A Developer's Guide prepares the reader to embrace the platform in easy-to-understand language and builds on this foundation with re-usable Java code examples. It is ideal for corporate and hobbyists alike who have an interest, or a mandate, to deliver software functionality for cell phones.    WHAT'S INSIDE:        * Android's place in the market      * Using the Eclipse environment for Android development      * The Intents - how and why they are used      * Application classes:            o Activity            o Service            o IntentReceiver       * User interface design      * Using the ContentProvider to manage data      * Persisting data with the SQLite database      * Networking examples      * Telephony applications      * Notification methods      * OpenGL, animation & multimedia      * Sample Applications  ",
    "status": "PUBLISH",
    "authors": [
      "W. Frank Ableson",
      "Charlie Collins",
      "Robi Sen"
    ],
    "categories": [
      "Open Source",
      "Mobile"
    ]
  },
  {
    "_id": 2,
    "title": "Android in Action, Second Edition",
    "isbn": "1935182722",
    "pageCount": 592,
    "publishedDate": {
      "$date": "2011-01-14T00:00:00.000-0800"
    },
    "thumbnailUrl": "https://s3.amazonaws.com/AKIAJC5RLADLUMVRPFDQ.book-thumb-images/ableson2.jpg",
    "shortDescription": "Android in Action, Second Edition is a comprehensive tutorial for Android developers. Taking you far beyond "Hello Android," this fast-paced book puts you in the driver's seat as you learn important architectural concepts and implementation strategies. You'll master the SDK, build WebKit apps using HTML 5, and even learn to extend or replace Android's built-in features by building useful and intriguing examples. ",
    "longDescription": "When it comes to mobile apps, Android can do almost anything   and with this book, so can you! Android runs on mobile devices ranging from smart phones to tablets to countless special-purpose gadgets. It's the broadest mobile platform available.    Android in Action, Second Edition is a comprehensive tutorial for Android developers. Taking you far beyond "Hello Android," this fast-paced book puts you in the driver's seat as you learn important architectural concepts and implementation strategies. You'll master the SDK, build WebKit apps using HTML 5, and even learn to extend or replace Android's built-in features by building useful and intriguing examples. ",
    "status": "PUBLISH",
    "authors": [
      "W. Frank Ableson",
      "Robi Sen"
    ],
    "categories": [
      "Java"
    ]
  },
  {
    "_id": 3,
    "title": "Specification by Example",
    "isbn": "1617290084",
    "pageCount": 0,
    "publishedDate": {
      "$date": "2011-06-03T00:00:00.000-0700"
    },
    "thumbnailUrl": "https://s3.amazonaws.com/AKIAJC5RLADLUMVRPFDQ.book-thumb-images/adzic.jpg",
    "status": "PUBLISH",
    "authors": [
      "Gojko Adzic"
    ],
    "categories": [
      "Software Engineering"
    ]
  }
]
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Solution for mapping list of object:

  static getBooksAll() async {
    var bookURL =
        "https://raw.githubusercontent.com/dineshnagarajandev/samplejson/main/books.json";
    var response = await http.get(Uri.parse(bookURL));
    var listToPass = jsonDecode(response.body);
    List<BookData> bookData =
        List<BookData>.from(listToPass.map((i) => BookData.fromJson(i)));
    print(bookData);
  }

Note: The Id class has type case issue which needs to be updated. The id you are using is int but declared as String

To check the solution comment

this.id = json["_id"] == null ? null : Id.fromJson(json["_id"]);

EDIT:

The model you are using is not having _id as an object. You can remove your ID class and update your model with bellow content

class BookData {
  int? id;
  String? title;
  String? isbn;
  int? pageCount;
  PublishedDate? publishedDate;
  String? thumbnailUrl;
  String? shortDescription;
  String? longDescription;
  String? status;
  List<dynamic>? authors;
  List<dynamic>? categories;

  BookData(
      {this.id,
      this.title,
      this.isbn,
      this.pageCount,
      this.publishedDate,
      this.thumbnailUrl,
      this.shortDescription,
      this.longDescription,
      this.status,
      this.authors,
      this.categories});

  BookData.fromJson(Map<String, dynamic> json) {
    this.id = json["_id"] == null ? null : json["_id"];
    this.title = json["title"];
    this.isbn = json["isbn"];
    this.pageCount = json["pageCount"];
    this.publishedDate = json["publishedDate"] == null
        ? null
        : PublishedDate.fromJson(json["publishedDate"]);
    this.thumbnailUrl = json["thumbnailUrl"];
    this.shortDescription = json["shortDescription"];
    this.longDescription = json["longDescription"];
    this.status = json["status"];
    this.authors = json["authors"] ?? [];
    this.categories = json["categories"] ?? [];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    if (this.id != null) data["_id"] = this.id;
    data["title"] = this.title;
    data["isbn"] = this.isbn;
    data["pageCount"] = this.pageCount;
    if (this.publishedDate != null)
      data["publishedDate"] = this.publishedDate?.toJson();
    data["thumbnailUrl"] = this.thumbnailUrl;
    data["shortDescription"] = this.shortDescription;
    data["longDescription"] = this.longDescription;
    data["status"] = this.status;
    if (this.authors != null) data["authors"] = this.authors;
    if (this.categories != null) data["categories"] = this.categories;
    return data;
  }
}

class PublishedDate {
  String? $date;

  PublishedDate({this.$date});

  PublishedDate.fromJson(Map<String, dynamic> json) {
    this.$date = json["${$date}"];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data["${$date}"] = this.$date;
    return data;
  }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...