I would like to do the unit test for model by Flutter.
Then I want to use test json data.
But I got the error message.
type 'List<dynamic>' is not a subtype of type 'Map<String, dynamic>' in type cast
I want to know how to solve this issue.
Here is the test codes.
void main() {
group('Gift Test', () {
test('Gift model test', () {
final file = File('json/gift_test.json').readAsStringSync();
final gifts = Gift.fromJson(jsonDecode(file) as Map<String, dynamic>);
expect(gifts.id, 999);
});
});
}
Here is the model
#freezed
abstract class Gift with _$Gift {
#Implements(BaseModel)
const factory Gift({
int id,
String name,
int amount,
Image image,
}) = _Gift;
factory Gift.fromJson(Map<String, dynamic> json) => _$GiftFromJson(json);
}
And this is the test data.
[
{
"id": 999,
"name": "testest",
"amount": 30000,
"image": {
"id": 9999,
"image": {
"url": "https://text.jpg",
},
},
}
]
Your json file is a list, not an object, either you change your json file in
{
"id": 999,
"name": "testest",
"amount": 30000,
"image": {
"id": 9999,
"image": {
"url": "https://text.jpg",
},
},
}
Or you will need to update your code to take the first element of the list:
final file = File('json/gift_test.json').readAsStringSync();
final gifts = Gift.fromJson((jsonDecode(file) as List).first as Map<String, dynamic>);
Related
I am using sqflite package for local Storage I need to store list of json in String, then Particular String again I need reconvert into Json list.
json
{
"images": [
{
"id": 10,
"name": "img1"
},
{
"id": 11,
"name": "img2"
}
]
}
Convert
import 'dart:convert';
final data = {
"images": [
{
"id": 10,
"name": "img1"
},
{
"id": 11,
"name": "img2"
}
],
};
final String dataAsJson = json.encode(data);
Inserting Data after opening database
import 'package:sqflite/sqflite.dart';
await db.insert(
'images', # the name of the table
{'data': dataAsJson}, # `data` is the column's name
);
Getting Data
final List<Map> maps = await db.query('images', columns: ['id', 'data']);
final dataFromJsonToMap = json.decode(maps[0]);
For my Calendar i get the following data as JSON from the Backend (*JAVA-Type = Map<LocalDate, List<Event>>):
{
"2022-05-28": [
{
"id": 2,
"title": "Multi day Event",
"fromDate": "2022-05-27T12:22:03.873569",
"toDate": "2022-05-28T11:22:03.873569",
"room": {
"id": 1,
"name": "TestRoom",
},
"user": {
"id": 1,
"name": "Andi",
"city": "",
"email": "test#gmail.com",
},
"eventType": "sozial"
}
],
"2022-05-27": [
{
"id": 2,
"title": "Multi day Event",
"fromDate": "2022-05-27T12:22:03.873569",
"toDate": "2022-05-28T11:22:03.873569",
"room": {
"id": 1,
"name": "TestRoom",
},
"user": {
"id": 1,
"name": "Andi",
"city": "",
"email": "test#gmail.com",
},
"eventType": "sozial"
},
{
"id": 1,
"title": "Testevent",
"fromDate": "2022-05-27T11:21:04.573754",
"toDate": "2022-05-27T12:21:04.573754",
"room": {
"id": 1,
"name": "TestRoom",
},
"user": {
"id": 1,
"name": "Andi",
"city": "",
"email": "test#gmail.com",
},
"eventType": "normal"
}
],
}
My Event Class looks like:
Class Event {
int id;
String title;
DateTime fromDate;
DateTime toDate;
Room room;
User user;
String eventType;
}
Now i need the same structure i had in the Backend (Map<DateTime, <List<Event>>) for my Calendar widget and i have no real clue on how to do it. I know how to convert json data into an object if i get a list of an object, but how can i store the date as key of the resulting map?
My code by now:
Future<Map<DateTime, List<Event>>> getEvents(DateTime _fromDate, DateTime
_endDate) async {
String _from = _fromDate.toString().split('.').first;
String _end = _endDate.toString().split('.').first;
final response = await get('${_url}calendar/events/$_from/$_end',
headers: {HttpHeaders.authorizationHeader: 'Bearer $_bearer'});
if (response.status.hasError) {
return Future.error('${response.statusText}');
} else {
final parsed = jsonDecode(response.body);
return parsed;
}
}
You need to do something like that:
var json = {...}; // <-- json obj
// method to parse data to map with list Event
dynamic fromJson(Map<String, dynamic> json){
var map = new Map();
json.keys.forEach((key){
// key is the date
map[key] = json[key].map((e) => Event.fromJson(e)).toList(); // <- need to create a method fromJson in your Event class
});
return map;
}
(...)
class Event {
int id;
String title;
DateTime fromDate;
DateTime toDate;
Room room;
User user;
String eventType;
fromJson(Map<String, dynamic> json) => Event(...); // <- parse json to Event class
}
I'm trying to get json data from Api by using the following
Future<SubjectList> getsubjectList(
String userId, String accountId) async {
final response = await http
.get(Uri.https(_baseUrl, 'v1/package/subject-details'), headers: {
'Content-Type': 'application/json',
'user-id': userId,
'account-id': accountId,
});
SubjectList jsonresponse = json.decode(response.body); //'_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'SubjectList'
print('This is response =$jsonresponse');
return jsonresponse;
}
I have modelled the object as follows
class SubjectList {
SubjectList({
this.subject,
this.score,
this.progress,
});
String? subject;
double? score;
String? progress;
factory SubjectList.fromMap(Map<String, dynamic> json) => SubjectList(
subject: json["subject"],
score: json["score"].toDouble(),
progress: json["progress"],
);
Map<String, dynamic> toJson() => {
"subject": subject,
"score": score,
"progress": progress,
};
}
The Data is as follows
{
"success": true,
"data": [
{
"subject": "Grammar",
"score": 57.17,
"progress": "96.77%"
},
{
"subject": "Maths",
"score": 52.12,
"progress": "73.08%"
},
{
"subject": "EVS",
"score": 55.75,
"progress": "97.96%"
},
{
"subject": "Social Studies",
"score": -1,
"progress": "-1%"
},
{
"subject": "Hindi",
"score": 51.36,
"progress": "60.87%"
},
{
"subject": "Vocabulary",
"score": 62.55,
"progress": "68.12%"
},
]
When ever i try to access using the model i'm receiving the error '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'SubjectList'. How do I get the data properly ?
Change this line
SubjectList jsonresponse = json.decode(response.body);
to something like
List<SubjectList> list = json.decode(response.body)['data'].map((d) => SubjectList.fromMap()).toList();
You can create a class for the response itself and the do the fromMap on it.
I am trying to get data from a local API into my project, i am facing the following problem:
Unhandled Exception: type 'List' is not a subtype of type 'Map<String, dynamic>'
// To parse this JSON data, do
//
// final toDo = toDoFromJson(jsonString);
import 'dart:convert';
import 'package:http/http.dart' as http;
ToDo toDoFromJson(String str) => ToDo.fromJson(json.decode(str));
String toDoToJson(ToDo data) => json.encode(data.toJson());
class ToDo {
ToDo({
required this.id,
required this.img,
required this.name,
required this.title,
required this.done,
required this.note,
required this.priority,
required this.dueDate,
required this.taskOwner,
required this.studentId,
required this.createdAt,
required this.updatedAt,
});
int id;
String img;
String name;
String title;
int done;
String note;
String priority;
String dueDate;
int taskOwner;
String studentId;
String createdAt;
String updatedAt;
factory ToDo.fromJson(Map<String, dynamic> json) => ToDo(
id: json["id"],
img: json["img"],
name: json["name"],
title: json["title"],
done: json["done"],
note: json["note"],
priority: json["priority"],
dueDate: json["due_date"],
taskOwner: json["TaskOwner"],
studentId: json["studentId"],
createdAt: json["createdAt"],
updatedAt: json["updatedAt"],
);
Map<String, dynamic> toJson() => {
"id": id,
"img": img,
"name": name,
"title": title,
"done": done,
"note": note,
"priority": priority,
"due_date": dueDate,
"TaskOwner": taskOwner,
"studentId": studentId,
"createdAt": createdAt,
"updatedAt": updatedAt,
};
}
Future<List<ToDo>> fetchTodos() async {
final response =
await http.get(Uri.parse('http://localhost:3000/task/all/1'));
if (response.statusCode == 200) {
final List<ToDo> todo = toDoFromJson(response.body) as List<ToDo>;
print(todo);
return todo;
} else {
print("nothing found");
return [];
}
}
Json from API is as below:
{
"id": 1,
"img": "assets/images/user/user1.jpg",
"name": "task 1",
"title": "eee",
"done": 0,
"note": "eee",
"priority": "Normal",
"due_date": "2021-07-06T18:30:00.000Z",
"TaskOwner": 1,
"studentId": "2",
"createdAt": "2021-07-26T14:39:54.000Z",
"updatedAt": "2021-07-26T14:39:54.000Z"
},
{
"id": 2,
"img": "assets/images/user/user1.jpg",
"name": "task 2",
"title": "nnjn",
"done": 0,
"note": "2525",
"priority": "High",
"due_date": "2021-07-19T18:30:00.000Z",
"TaskOwner": 1,
"studentId": "7",
"createdAt": "2021-07-27T15:05:31.000Z",
"updatedAt": "2021-07-27T15:05:31.000Z"
},
{
"id": 3,
"img": "assets/images/user/user1.jpg",
"name": "task 3",
"title": "5255",
"done": 0,
"note": "55",
"priority": "Normal",
"due_date": "2021-07-21T18:30:00.000Z",
"TaskOwner": 1,
"studentId": "7",
"createdAt": "2021-07-27T15:05:48.000Z",
"updatedAt": "2021-07-27T15:05:48.000Z"
},
{
"id": 4,
"img": "assets/images/user/user1.jpg",
"name": "task 4",
"title": "kaam kro",
"done": 0,
"note": "test note",
"priority": "Normal",
"due_date": "2021-07-21T18:30:00.000Z",
"TaskOwner": 1,
"studentId": "2",
"createdAt": "2021-08-04T14:45:47.000Z",
"updatedAt": "2021-08-04T14:45:47.000Z"
},
The method you are using to parse todos will return a ToDo object casted to a List<ToDo> which will cause an exception!
What you have to do is converting every single map in json to ToDo and then create a List from them.
Here is what you need to do:
replace this line
final List<ToDo> todo = toDoFromJson(response.body) as List<ToDo>;
with this:
final List<ToDo> todo = List<ToDo>.from(response.body.map((x) => toDoFromJson(x)))
fixed this by adding for loop to the Future function, refer to the code below -
Future<List<ToDo>> fetchTodos() async {
List<ToDo> todos = [];
final response =
await http.get(Uri.parse('https://dhulltransport.com:20625/task/all/1'));
if (response.statusCode == 200) {
var jsonList = jsonDecode(response.body);
for (var t in jsonList) {
todos.add(ToDo.fromJson(t));
}
print(todos.length);
return todos;
} else {
return [];
}
}
I spent days to think&googled about how to achieve this, but still can't get any idea how it actually works...
I would appreciate if someone could give me some advise or point me to the right direction.
So in my case, I will fetch a json list from an APIs, and I just wanna store the Shop class into a list which will build in a listView.
Here's my code sample.
Widget buildShopList() {
return ListView.builder(
itemCount: shopList.length,
padding: const EdgeInsets.only(top: 8, bottom: 110),
scrollDirection: Axis.vertical,
itemBuilder: (BuildContext context, int index) {
final int count = shopList.length > 10 ? 10 : shopList.length;
return ShopListView(
callback: () {},
shop: shopList[index],
);
},
);
}
class ShopListView extends StatelessWidget {
const ShopListView({Key key, this.shop}: super(key: key);
final Shop shop;
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(shop.type.name),
Text(shop.name),
]
);
}
}
Shop model class
class Shop {
String name;
String website;
String email;
ShopType type;
Shop({this.name, this.website, this.email, this.type});
factory Shop.fromJson(Map<String, dynamic> json) => Shop(
name: json["name"],
type: json["shop_types"],
// can't figure out how to pass the shop type model class into here
website: json["website"],
email: json["email"],
);
Map<String, dynamic> toJson() => {
"name": name,
"shop_types": type,
"website": website,
"email": email
};
}
ShopType model class
class ShopType {
int id;
String name;
String description;
ShopType({this.id, this.name, this.description});
factory ShopType.fromJson(Map<String, dynamic> json) => ShopType(
id: json["id"],
name: json["name"],
description: json["description"],
);
Map<String, dynamic> toJson() => {
"id": id,
"name": name,
"description": description,
};
}
Here's the json will response from APIs
{
"success": true,
"data": {
"shops": [
{
"id": 1,
"name": "shop name a",
"website": "http://www.test.com/",
"email": "test#test.com",
"description": "this is a dummy data",
"shop_types": [
{
"id": 1,
"name": "Type A",
"description": "Type A",
"pivot": {
"shop_id": 1,
"shop_type_id": 1
}
}
]
},
{
"id": 2,
"name": "shop name b",
"website": "http://www.test.com/",
"email": "test#test.com",
"description": "this is a dummy data",
"shop_types": [
{
"id": 2,
"name": "Store",
"description": "Store",
"pivot": {
"shop_id": 2,
"shop_type_id": 2
}
}
]
},
{
"id": 3,
"name": "shop name c",
"website": "http://www.test.com/",
"email": "test#test.com",
"description": "this is a dummy data",
"shop_types": [
{
"id": 1,
"name": "Type A",
"description": "Type A",
"pivot": {
"shop_id": 3,
"shop_type_id": 1
}
},
{
"id": 2,
"name": "Type B",
"description": "Type B",
"pivot": {
"shop_id": 3,
"shop_type_id": 2
}
}
]
}
],
"shopTypes": [
{
"id": 1,
"name": "Type A",
"description": "Type A",
},
{
"id": 2,
"name": "Type B",
"description": "Type B",
}
]
}
}
Fetch data From network with Dio
fetchShopsAndSaveLocal() async{
var dio = Dio();
dio.options.connectTimeout = 4500 * 10; //45s
dio.options.receiveTimeout = 4500 * 10;
try {
var param = {
"useremail": "dpk.7#gmail.com"
, "password": "123456"};
var response = await dio.post(
"https://api.test/getstores", data: FormData.fromMap(param));
var json = jsonDecode(response.data);
ModelStore store = ModelStore.fromJson(json);
List<Shops> shops = store.shops;
for (var shop in shops) {
saveEverySingleShopInDatabase(shop);
}
} catch (e) {}
}
After that use SQFlite
To Save shops data in Database, after saving data in the local database, fetch data to listview every time from the database.