Home > OS >  How to parse List<Review> from List<dynamic> in fromJson
How to parse List<Review> from List<dynamic> in fromJson

Time:04-28

I have two models: book and review.

In book.dart, I have a field to list down the reviews (defined in review.dart) associated with this book.

class Book {
  final String id;
  final String bookid;
  final String title;
  final String author;
  final DateTime purchDate;
  final String intro;
  final List<Review> reviews;

  Book(this.id, this.bookid, this.title, this.author, this.purchDate,
      this.intro, this.reviews);

  Book.fromJson(Map<String, dynamic> json)
      : id = json['id'].toString(),
        bookid = json['bookid'],
        title = json['title'],
        author = json['author'],
        purchDate = DateTime.parse(json['purchdate']),
        intro = json['intro'],
        reviews = json['reviews'];
}

And this is the review.dart:

class Review {
  final int id;
  final String title;
  final DateTime datein;
  final String uri;

  Review(this.id, this.title, this.datein, this.uri);
  Review.fromJson(Map<String, dynamic> json)
      : id = json['id'],
        title = json['title'],
        datein = DateTime.parse(json['datein']),
        uri = json['URI'];
}

The unit test for review model works fine.

However, when I tried to run a unit test for book model:

import 'dart:convert';

import 'package:test/test.dart';
import 'package:rsywx/model/book.dart';
import 'package:http/http.dart' as http;

void main() {
  test('Retrieve a book with review(s)', () async {
    var uri = 'https://api';
    var res = await http.get(Uri.parse(uri));

    var result = jsonDecode(res.body)['data'];
    var book = Book.fromJson(result);

    expect(book.id, '666');
    expect(book.author, '卡尔维诺');
    expect(book.reviews.length, 2);
    expect(book.reviews[0] is Map<String, dynamic>, true);
    expect(book.reviews[1] is Map<String, dynamic>, true);
  });
}

An error occurs:

00:04  0 -1: Retrieve a book with review(s) [E]                                                                                                      
  type 'List<dynamic>' is not a subtype of type 'List<Review>'
  package:rsywx/model/book.dart 22:17  new Book.fromJson
  test/book_test.dart 13:21            main.<fn>

I understand that from my http.get and jsonDecode, the result has no way to determine or show that the field reviews is actually a List<Reviews>. So the error appears.

I can eliminate this particular error by changing the book model definition, in particular: from List<Review> reviews to List<dynamic> reviews. But I want to have a stronger type control.

Thanks for the help.

CodePudding user response:

in book.dart

class Book {
  final String id;
  final String bookid;
  final String title;
  final String author;
  final DateTime purchDate;
  final String intro;
  final List<Review> reviews;

  Book(this.id, this.bookid, this.title, this.author, this.purchDate,
      this.intro, this.reviews);

  Book.fromJson(Map<String, dynamic> json)
      : id = json['id'].toString(),
        bookid = json['bookid'],
        title = json['title'],
        author = json['author'],
        purchDate = DateTime.parse(json['purchdate']),
        intro = json['intro'],
        reviews = (json['reviews'] as List).map((e)=>Review.fromdynamic(e)).toList();
}

in review.dart

class Review {
  final int id;
  final String title;
  final DateTime datein;
  final String uri;

  Review(this.id, this.title, this.datein, this.uri);
  Review.fromdynamic(dynamic json)
      : id = json['id'],
        title = json['title'],
        datein = DateTime.parse(json['datein']),
        uri = json['URI'];
}

CodePudding user response:

@Ye Myo Aung's answer is fine. But I would recommend to avoid dynamic type parameters. So I would change Review's named constructor to:

Review.fromJson(Map<String, dynamic> json)
      : id = json['id'],
        title = json['title'],
        datein = DateTime.parse(json['datein']),
        uri = json['URI'];

And the the Book's fromJson it changes to:

Book.fromJson(Map<String, dynamic> json)
    : id = json['id'].toString(),
      bookid = json['bookid'],
      title = json['title'],
      author = json['author'],
      purchDate = DateTime.parse(json['purchdate']),
      intro = json['intro'],
      reviews = (json['reviews'] as List)
        .map((e) => Review.fromJson(e as Map<String, dynamic>))
        .toList();
  • Related