Related
I’m trying to parse one object from a Json response. My response.data is of type ‘_InternalLinkedHashMap<String, dynamic>’. I would like to transform it to the type of my object. So for doing that I use the method fromJson of my class.
Class code:
import 'dart:convert';
import 'package:.../stl/store_stl.dart';
class StoreSTLModel extends StoreSTL {const StoreSTLModel({
required String storeId,
required String storeName,
required String subContextUrl,
required List<dynamic> openingEvent,
required List<dynamic> closingEvent,
}) : super(
storeId: storeId,
storeName: storeName,
subContextUrl: subContextUrl,
openingEvent: openingEvent,
closingEvent:closingEvent ,
);
Map<String, dynamic> toMap() {
return <String, dynamic>{
'storeId': storeId,
'storeName': storeName,
'subContextUrl': subContextUrl,
'openingEvent': openingEvent.toList(),
'closingEvent': closingEvent.toList(),
};
}
factory StoreSTLModel.fromMap(Map<String, dynamic> map) {
return StoreSTLModel(
storeId: map['storeId'] as String ,
storeName: map["storeName"] as String,
subContextUrl: map["subContextUrl"] as String,
openingEvent: List<dynamic>.from(map["openingEvent"] as List<dynamic>),
closingEvent: List<dynamic>.from(map["closingEvent"] as List<dynamic>),
);
}
String toJson() => json.encode(toMap());
factory StoreSTLModel.fromJson(String source) => StoreSTLModel.fromMap(json.decode(source) as Map<String, dynamic>);
}
the code of my request is as follow: (I’m using Dio package)
import 'package:.../app_constants.dart';
import 'package:dio/dio.dart';
import 'package:...stl/store_stl_model.dart';
class RemoteStoreSTLDataSource {
static dynamic apiSTLData;
static late final urlApiSTL = AppConstants.urlApiSTL;
//get store from api STL (for now store id is hardcode)
Future<StoreSTLModel> getStoreFromSTL() async{
if(apiSTLData == null){
apiSTLData = {};
try{
Response? response = await Dio().get(
urlApiSTL,
);
apiSTLData = response.data;
print('apiSTLData type response.data ${ apiSTLData.runtimeType}');
//prints: apiSTLData type response.data _InternalLinkedHashMap<String, dynamic>
}on Exception {
null;
print('apiSTLData Exception');
}
}
print('apiSTLData type response.data[store] ${apiSTLData['store'].runtimeType}');
//prints: apiSTLData type response.data[store] _InternalLinkedHashMap<String, dynamic>
return StoreSTLModel.fromJson(apiSTLData['store']);
}
}
when I try to run, I’m having the error:
Unhandled Exception: type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'String'
so I don’t understand why it is not being parsed. and I don’t understand why the response is of this type ‘_InternalLinkedHashMap<String, dynamic>’ I'm a beginner in Dart. Could you please help me to understand. Thanks in advance :)
{
"store": {
"storeId": "30264",
"storeName": "xxxxx",
"subContextUrl": "hxxxu-xxxxx",
"type": "STORE",
"address": {
"label": null,
"zipcode": "xxxx",
"city": "xxxx",
"countryCode": "xxxx",
"lines": [
"xxxxxxxx",
""
]
},
"openingEvent": [],
"closingEvent": [],
"dayHours": {
"day": "THURSDAY",
"morningOpeningHour": "08:30:00",
"morningClosingHour": null,
"afternoonOpeningHour": null,
"afternoonClosingHour": "20:00:00"
},
"driveHours": {
"timezone": "xxxxxx",
"openHourList": [
{
"day": "MONDAY",
"morningOpeningHour": "08:30:00",
"morningClosingHour": null,
"afternoonOpeningHour": null,
"afternoonClosingHour": "20:00:00"
},
{
"day": "SUNDAY",
"morningOpeningHour": null,
"morningClosingHour": null,
"afternoonOpeningHour": null,
"afternoonClosingHour": null
}
]
},
"eservices": [
{
"website": "serviceWebsite - to be defined",
"linkTitle": null,
"linklabel": null,
"serviceId": 2,
"serviceName": "xxxxxx"
},
{
"website": "serviceWebsite - to be defined",
"linkTitle": null,
"linklabel": null,
"serviceId": 4,
"serviceName": "xxxxxx"
},
{
"website": "serviceWebsite - to be defined",
"linkTitle": null,
"linklabel": null,
"serviceId": 39,
"serviceName": "xxxxx"
}
],
"services": [
"xxxxxx",
"xxxxx",
"xxxxxxx"
],
"additionalStoreInfo": {
"status": "xxxxx",
"commercialSignLabel": "xxxxx"
}
}
}
This is model class
import 'dart:convert';
class StoreSTLModel {
StoreSTLModel({
required this.store,
});
final Store store;
factory StoreSTLModel.fromJson(String str) => StoreSTLModel.fromMap(json.decode(str));
factory StoreSTLModel.fromMap(Map<String, dynamic> json) => StoreSTLModel(
store: Store.fromMap(json["store"]),
);
Map<String, dynamic> toMap() => {
"store": store.toMap(),
};
}
class Store {
Store({
required this.storeId,
required this.storeName,
required this.subContextUrl,
required this.type,
required this.address,
required this.openingEvent,
required this.closingEvent,
required this.dayHours,
required this.driveHours,
required this.eservices,
required this.services,
required this.additionalStoreInfo,
});
final String storeId;
final String storeName;
final String subContextUrl;
final String type;
final Address address;
final List<dynamic> openingEvent;
final List<dynamic> closingEvent;
final DayHours dayHours;
final DriveHours driveHours;
final List<Eservice> eservices;
final List<String> services;
final AdditionalStoreInfo additionalStoreInfo;
factory Store.fromMap(Map<String, dynamic> json) => Store(
storeId: json["storeId"],
storeName: json["storeName"],
subContextUrl: json["subContextUrl"],
type: json["type"],
address: Address.fromMap(json["address"]),
openingEvent: List<dynamic>.from(json["openingEvent"].map((x) => x)),
closingEvent: List<dynamic>.from(json["closingEvent"].map((x) => x)),
dayHours: DayHours.fromMap(json["dayHours"]),
driveHours: DriveHours.fromMap(json["driveHours"]),
eservices: List<Eservice>.from(json["eservices"].map((x) => Eservice.fromMap(x))),
services: List<String>.from(json["services"].map((x) => x)),
additionalStoreInfo: AdditionalStoreInfo.fromMap(json["additionalStoreInfo"]),
);
Map<String, dynamic> toMap() => {
"storeId": storeId,
"storeName": storeName,
"subContextUrl": subContextUrl,
"type": type,
"address": address.toMap(),
"openingEvent": List<dynamic>.from(openingEvent.map((x) => x)),
"closingEvent": List<dynamic>.from(closingEvent.map((x) => x)),
"dayHours": dayHours.toMap(),
"driveHours": driveHours.toMap(),
"eservices": List<dynamic>.from(eservices.map((x) => x.toMap())),
"services": List<dynamic>.from(services.map((x) => x)),
"additionalStoreInfo": additionalStoreInfo.toMap(),
};
}
class AdditionalStoreInfo {
AdditionalStoreInfo({
required this.status,
required this.commercialSignLabel,
});
final String status;
final String commercialSignLabel;
factory AdditionalStoreInfo.fromMap(Map<String, dynamic> json) => AdditionalStoreInfo(
status: json["status"],
commercialSignLabel: json["commercialSignLabel"],
);
Map<String, dynamic> toMap() => {
"status": status,
"commercialSignLabel": commercialSignLabel,
};
}
class Address {
Address({
required this.label,
required this.zipcode,
required this.city,
required this.countryCode,
required this.lines,
});
final dynamic label;
final String zipcode;
final String city;
final String countryCode;
final List<String> lines;
factory Address.fromMap(Map<String, dynamic> json) => Address(
label: json["label"],
zipcode: json["zipcode"],
city: json["city"],
countryCode: json["countryCode"],
lines: List<String>.from(json["lines"].map((x) => x)),
);
Map<String, dynamic> toMap() => {
"label": label,
"zipcode": zipcode,
"city": city,
"countryCode": countryCode,
"lines": List<dynamic>.from(lines.map((x) => x)),
};
}
class DayHours {
DayHours({
required this.day,
required this.morningOpeningHour,
required this.morningClosingHour,
required this.afternoonOpeningHour,
required this.afternoonClosingHour,
});
final String day;
final String morningOpeningHour;
final dynamic morningClosingHour;
final dynamic afternoonOpeningHour;
final String afternoonClosingHour;
factory DayHours.fromMap(Map<String, dynamic> json) => DayHours(
day: json["day"],
morningOpeningHour: json["morningOpeningHour"],
morningClosingHour: json["morningClosingHour"],
afternoonOpeningHour: json["afternoonOpeningHour"],
afternoonClosingHour: json["afternoonClosingHour"],
);
Map<String, dynamic> toMap() => {
"day": day,
"morningOpeningHour": morningOpeningHour,
"morningClosingHour": morningClosingHour,
"afternoonOpeningHour": afternoonOpeningHour,
"afternoonClosingHour": afternoonClosingHour,
};
}
class DriveHours {
DriveHours({
required this.timezone,
required this.openHourList,
});
final String timezone;
final List<DayHours> openHourList;
factory DriveHours.fromMap(Map<String, dynamic> json) => DriveHours(
timezone: json["timezone"],
openHourList: List<DayHours>.from(json["openHourList"].map((x) => DayHours.fromMap(x))),
);
Map<String, dynamic> toMap() => {
"timezone": timezone,
"openHourList": List<dynamic>.from(openHourList.map((x) => x.toMap())),
};
}
class Eservice {
Eservice({
required this.website,
required this.linkTitle,
required this.linklabel,
required this.serviceId,
required this.serviceName,
});
final String website;
final dynamic linkTitle;
final dynamic linklabel;
final int serviceId;
final String serviceName;
factory Eservice.fromMap(Map<String, dynamic> json) => Eservice(
website: json["website"],
linkTitle: json["linkTitle"],
linklabel: json["linklabel"],
serviceId: json["serviceId"],
serviceName: json["serviceName"],
);
Map<String, dynamic> toMap() => {
"website": website,
"linkTitle": linkTitle,
"linklabel": linklabel,
"serviceId": serviceId,
"serviceName": serviceName,
};
}
This is Dio class
import 'dart:convert';
import 'package:.../app_constants.dart';
import 'package:dio/dio.dart';
import 'package:...stl/store_stl_model.dart';
class RemoteStoreSTLDataSource {
static dynamic apiSTLData;
static late final urlApiSTL = AppConstants.urlApiSTL;
Future<StoreSTLModel> getStoreFromSTL() async{
if(apiSTLData == null){
apiSTLData = {};
try{
final response = await Dio().get(
urlApiSTL,
);
apiSTLData = response.data;
if (response.statusCode == 200) {
//Try them, one of them will work.
return StoreSTLModel.fromMap(apiSTLData);
return StoreSTLModel.fromJson(apiSTLData);
} else {
throw Exception("404 error");
}
} on DioError catch (e) {
return Future.error(e.message);
}
}
}
}
Try this.
I am using this structure -
return (details['home_store'] as List).map((e) => DetailsModel.fromJson(e)).toList();
When I receive data from the server in this format -
{
"homestore": [
{
"id": 1,
},
]
}
And what should I do when the data comes in this format?
{
"id": 1,
},
Try this
DetailsModel.fromJson(details)
Or if you have several elements
class DetailsModel {
final String id;
final String name;
final String age;
DetailsModel({
required this.id,
required this.name,
required this.age,
});
factory DetailsModel.fromJson(Map<String, dynamic> details) {
return DetailsModel(
id: details['id'],
name: details['name'],
age: details['age'],
);
}
}
Just edit your Model class. You can add more fields to it.
I'm trying to parse a json file using a custom model, I always get the error type 'List<dynamic>' is not a subtype of type 'List<BusinessTest>' and I don't know how I can fix my code. Also is it a good idea to always use nullable type in variables when you parse json files?
This is a Json example of my data:
{
"businesses": [{
"id": "1",
"alias": "123",
"name": "aaa",
"image_url": "xxx.jpg",
"is_closed": false,
"url": ".com",
"review_count": 26,
"rating": 5.0
},
{
"id": "2",
"alias": "123",
"name": "aaa",
"image_url": "xxx.jpg",
"is_closed": false,
"url": ".com",
"review_count": 26,
"rating": 5.0
}
]
}
Here is the model code I've made in order to parse the Json:
class BusinessSearch {
final List<BusinessTest> businesses;
final int total;
BusinessSearch(this.businesses, this.total);
BusinessSearch.fromJson(Map<String, dynamic> json)
: businesses = json['businesses'],
total = json['total'];
}
class BusinessTest {
final String? name;
final String? imageUrl;
final bool? isClosed;
final String? url;
final int? reviewCount;
BusinessTest(
this.name, this.imageUrl, this.isClosed, this.url, this.reviewCount);
BusinessTest.fromJson(Map<String, dynamic> json)
: name = json['name'],
imageUrl = json['image_url'],
isClosed = json['is_closed'],
url = json['url'],
reviewCount = json['review_count'];
}
This is how I'm trying to parse it:
void getData() async {
try {
String url = 'url';
NetworkHelp network = NetworkHelp(url: url);
var data = await network.getData();
Map<String, dynamic> businessMap = await jsonDecode(data);
var business = BusinessSearch.fromJson(businessMap);
} catch (e) {
print(e);
}
}
You have to update your BusinessSearch model like this.
class BusinessSearch {
BusinessSearch({
this.businesses,
this.total,
});
List<Business> businesses = [];
int total;
factory BusinessSearch.fromJson(Map<String, dynamic> json) => BusinessSearch(
businesses: List<Business>.from(json["businesses"].map((x) => Business.fromJson(x))),
total: json['total']
);
Map<String, dynamic> toJson() => {
"businesses": List<dynamic>.from(businesses.map((x) => x.toJson())),
"total": total,
};
}
class Business {
Business({
this.id,
this.alias,
this.name,
this.imageUrl,
this.isClosed,
this.url,
this.reviewCount,
this.rating,
});
String id;
String alias;
String name;
String imageUrl;
bool isClosed;
String url;
int reviewCount;
int rating;
factory Business.fromJson(Map<String, dynamic> json) => Business(
id: json["id"],
alias: json["alias"],
name: json["name"],
imageUrl: json["image_url"],
isClosed: json["is_closed"],
url: json["url"],
reviewCount: json["review_count"],
rating: json["rating"],
);
Map<String, dynamic> toJson() => {
"id": id,
"alias": alias,
"name": name,
"image_url": imageUrl,
"is_closed": isClosed,
"url": url,
"review_count": reviewCount,
"rating": rating,
};
}
the json I receive from the api looks like this:
{
"USD": [
{
"name": "something",
"value": 123
},
{
"name": "something else",
"value": 1234
}
],
"EUR": [
... same here
]
}
and my dart model looks like:
#JsonSerializable(anyMap: true, includeIfNull: true)
class StatisticsDto {
StatisticsDto({this.statistics});
final Map<String, List<StatisticsDetailDto>> statistics;
factory StatisticsDto.fromJson(Map<String, dynamic> json) =>
_$StatisticsDtoFromJson(json);
Map<String, dynamic> toJson() => _$StatisticsDtoToJson(this);
}
#JsonSerializable()
class StatisticsDetailDto {
StatisticsDetailDto({
this.name,
this.value,
});
final String name;
final num value;
factory StatisticsDetailDto.fromJson(Map<String, dynamic> json) =>
_$StatisticsDetailDtoFromJson(json);
Map<String, dynamic> toJson() => _$StatisticsDetailDtoToJson(this);
}
I don't seem to be able to make it work, I get a 200 from the api, but the serialization returns null.
What am I doing wrong here?
This is what your JSON objects should look like converted to Dart data class with json_serializable
{
"USD": [{
"name": "something",
"value": 123
},
{
"name": "something else",
"value": 1234
}
],
"EUR": [{
"name": "something",
"value": 123
},
{
"name": "something else",
"value": 1234
}
]
}
Dart data class with json_serializable without Map support:
import 'package:json_annotation/json_annotation.dart';
part 'statistic_dto.g.dart';
part 'currency.g.dart';
#JsonSerializable()
class StatisticDto {
StatisticDto({this.usd, this.eur});
#JsonKey(name: 'USD')
List<Currency>? usd;
#JsonKey(name: 'EUR')
List<Currency>? eur;
factory StatisticDto.fromJson(Map<String, dynamic> json) {
return _$StatisticDtoFromJson(json);
}
Map<String, dynamic> toJson() => _$StatisticDtoToJson(this);
}
#JsonSerializable()
class Currency {
Currency({this.name, this.value});
String? name;
int? value;
factory Currency.fromJson(Map<String, dynamic> json) => _$CurrencyFromJson(json);
Map<String, dynamic> toJson() => _$CurrencyToJson(this);
}
Run:
flutter pub run build_runner build --delete-conflicting-outputs
In your first example, your Map statistics have no key that why it always returns null. JSON file would look like this for your first class Data
// For: final Map<String, Map<String, dynamic>> statistics;
{
"statistics": {
"USD": {
"name": "One",
"value": 1
},
"EUR": {
"name": "Four",
"value": 4
}
}
}
If you are looking to serialize a json with fixed keys, please refer to Arnas' answer.
In my case, the json has dynamic keys, e.g. it's a map with an indefinite number of keys (corresponding to a currency code in my case), and a corresponding value (an array of objects).
Now, I reckon #JsonSerializable is not suitable for this kind of scenario, hence I implemented my own .fromJson() factories.
class StatisticsDto {
StatisticsDto({this.statistics});
final Map<String, List<StatisticsDetailDto>> statistics;
factory StatisticsDto.fromJson(Map<String, dynamic> json) =>
StatisticsDto(
statistics: json.map((String currency, dynamic details) {
final List<StatisticsDetailDto> currencyDetails = details
.map<StatisticsDetailDto>(
(detail) => StatisticsDetailDto.fromJson(detail))
.toList();
return MapEntry<String, List<StatisticsDetailDto>>(currency, currencyDetails);
})
);
}
class StatisticsDetailDto {
StatisticsDetailDto({
this.name,
this.value,
});
final String name;
final num value;
factory StatisticsDetailDto.fromJson(Map<String, dynamic> json) =>
StatisticsDetailDto(
type: json['name'],
value: json['value'],
);
}
hi stackers i have a problem with returning nested data in array object using flutter, the data has shown but i cant get what i want to get i have a response like this from my backend
"meta": {
"code": 200,
"status": "success",
"message": "Data list transaksi berhasil diambil"
},
"data": {
"current_page": 1,
"data": [
{
"id": 1,
"users_id": 1,
"invoice": "INV38972",
"seat_number": 2,
"total_price": 1000,
"payment_method": "TUNAI",
"status": "PENDING",
"items": [
{
"id": 1,
"menus_id": 1,
"transactions_id": 1,
"quantity": 5,
"menus": {
"id": 1,
"name": "Adidas NMD",
"price": 200,
"description": "Ini adalah sepatu sport",
"categories_id": 1,
}
}
]
}
],
}
}
response above is from my backend that success fully return in my response print() in flutter but i want to get the nested data in items.menus its return error Class'_InternalLinkedHashMap<String, dynamic>'has no instance getter 'menus'
for better understanding my question ill provide full model, provider and my services
this is my service getOrderList() function that i call in the futureBuilder
var url = '$baseUrl/transaction';
var headers = {
'Content-type': 'application/json',
'Authorization': 'Bearer ${userModel.token}'
};
var response = await http.get(Uri.parse(url), headers: headers);
// print(response.body);
// print('berhasil get kategori');
if (response.statusCode == 200) {
List data = json.decode(response.body)['data']['data'];
List<TransactionModel> transaction = [];
for (var item in data) {
transaction.add(TransactionModel.fromJson(item));
}
// print(transaction);
return transaction;
} else {
throw Exception('Gagal get Categori');
}
}
and this is my model code
class TransactionModel {
int id;
int users_id;
String invoice;
int seat_number;
double total_price;
String payment_method;
String status;
List items;
// List menu;
TransactionModel({
this.id,
this.users_id,
this.invoice,
this.seat_number,
this.total_price,
this.payment_method,
this.status,
this.items,
// this.menu,
});
TransactionModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
users_id = json['users_id'];
invoice = json['invoice'];
seat_number = json['seat_number'];
total_price = double.parse(json['total_price'].toString());
payment_method = json['payment_method'];
status = json['status'];
items = json['items'];
// menu = json['items']['menus'];
}
Map<String, dynamic> toJson() {
return {
'id': id,
'users_id': users_id,
'invoice': invoice,
'seat_number': seat_number,
'items': items,
'total_price': total_price,
'payment_method': payment_method,
'status': status,
// 'menu': menu,
};
}
}
i already change the model data and try much method but its still not working, thats all on my code what should i do to call items.menus in result ?
It seems to be a problem within the model, you can use a json to dart to make model class from raw json. Keep the fetching logic as it is.
Json
{
"id": 1,
"users_id": 1,
"invoice": "INV38972",
"seat_number": 2,
"total_price": 1000,
"payment_method": "TUNAI",
"status": "PENDING",
"items": [
{
"id": 1,
"menus_id": 1,
"transactions_id": 1,
"quantity": 5,
"menus": {
"id": 1,
"name": "Adidas NMD",
"price": 200,
"description": "Ini adalah sepatu sport",
"categories_id": 1
}
}
]
}
Model class
// To parse this JSON data, do
//
// final transactionModel = transactionModelFromMap(jsonString);
import 'dart:convert';
class TransactionModel {
TransactionModel({
this.id,
this.usersId,
this.invoice,
this.seatNumber,
this.totalPrice,
this.paymentMethod,
this.status,
this.items,
});
final int id;
final int usersId;
final String invoice;
final int seatNumber;
final int totalPrice;
final String paymentMethod;
final String status;
final List<Item> items;
factory TransactionModel.fromJson(String str) => TransactionModel.fromMap(json.decode(str));
String toJson() => json.encode(toMap());
factory TransactionModel.fromMap(Map<String, dynamic> json) => TransactionModel(
id: json["id"],
usersId: json["users_id"],
invoice: json["invoice"],
seatNumber: json["seat_number"],
totalPrice: json["total_price"],
paymentMethod: json["payment_method"],
status: json["status"],
items: List<Item>.from(json["items"].map((x) => Item.fromMap(x))),
);
Map<String, dynamic> toMap() => {
"id": id,
"users_id": usersId,
"invoice": invoice,
"seat_number": seatNumber,
"total_price": totalPrice,
"payment_method": paymentMethod,
"status": status,
"items": List<dynamic>.from(items.map((x) => x.toMap())),
};
}
class Item {
Item({
this.id,
this.menusId,
this.transactionsId,
this.quantity,
this.menus,
});
final int id;
final int menusId;
final int transactionsId;
final int quantity;
final Menus menus;
factory Item.fromJson(String str) => Item.fromMap(json.decode(str));
String toJson() => json.encode(toMap());
factory Item.fromMap(Map<String, dynamic> json) => Item(
id: json["id"],
menusId: json["menus_id"],
transactionsId: json["transactions_id"],
quantity: json["quantity"],
menus: Menus.fromMap(json["menus"]),
);
Map<String, dynamic> toMap() => {
"id": id,
"menus_id": menusId,
"transactions_id": transactionsId,
"quantity": quantity,
"menus": menus.toMap(),
};
}
class Menus {
Menus({
this.id,
this.name,
this.price,
this.description,
this.categoriesId,
});
final int id;
final String name;
final int price;
final String description;
final int categoriesId;
factory Menus.fromJson(String str) => Menus.fromMap(json.decode(str));
String toJson() => json.encode(toMap());
factory Menus.fromMap(Map<String, dynamic> json) => Menus(
id: json["id"],
name: json["name"],
price: json["price"],
description: json["description"],
categoriesId: json["categories_id"],
);
Map<String, dynamic> toMap() => {
"id": id,
"name": name,
"price": price,
"description": description,
"categories_id": categoriesId,
};
}