Flutter json_serializable: fromJson returns null - flutter

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'],
);
}

Related

Dio no parsing Unhandled Exception: type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'String'

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.

Flutter - Dart parsing json data array returns type 'List<dynamic>' is not a subtype of type 'List<BusinessTest>'

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,
};
}

Factory of object

I've a dataset like this:
"items": [
{
"title": "title1",
"photos": [...],
"value": {}
},
{
"title": "title2",
"photos": [...],
"value": {
"apple": "something",
"pear": "lorem ipsum",
}
}
]
So I created two classes:
class Value {
final String apple;
final String pear;
Value({
required this.apple,
required this.pear,
});
factory Value.fromJson(Map<dynamic, dynamic> json) {
return Value(
apple: json['apple'],
pear: json['pear'],
);
}
}
class Item {
final String title;
final List<String> photos;
final Value value;
Item({
required this.title,
required this.photos,
required this.value,
});
factory Item.fromJson(Map<dynamic, dynamic> json) {
return Item(
title: json['title'],
photos: json['photos'],
value: json['value'] // <-- ??
);
}
}
But when I create the data, I get Error: Expected a value of type 'String', but got one of type '_JsonMap'.
I tried to cast to Value but I get error again.
How can I solve?
As the json['value] is a JSON Object you need to parse it like below and assign it to the value.
Value.fromJson(json['value'] as Map<String, dynamic>)
so your model will look like below:
value: Value.fromJson(json['value'] as Map<String, dynamic>)

Flutter: The element type 'Map<dynamic, String>' can't be assigned to the list type 'Player'

Future signInWithEmailAndPassword(String email, String password) async { ... await DatabaseService(uid: user!.uid).updateUserData(UserData( player:[{name:'name',rol:'rol'}], }
I cant inizialite player, error: The element type 'Map<dynamic, String>' can't be assigned to the list type 'Player'.
class UserData { final List<Player> player; UserData({required this.player}) }
class Player{final String name;final String rol; Player({required this.name, required this.rol});}
Your error says that the method updateUserData() is receiving the Player class instead of a map().
In this case, you can create a method in UserData class, called UserData.toJson().
Supposing your Json should be like this:
{
"player": [
{
"name": "name",
"rol": "rol"
},
{
"name": "name",
"rol": "rol"
},
{
"name": "name",
"rol": "rol"
}
]
}
Your UserData and Player classes should be like this:
import 'dart:convert';
UserData userDataFromJson(String str) => UserData.fromJson(json.decode(str));
String userDataToJson(UserData data) => json.encode(data.toJson());
class UserData {
UserData({
this.player,
});
List<Player> player;
factory UserData.fromJson(Map<String, dynamic> json) => UserData(
player: List<Player>.from(json["player"].map((x) => Player.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"player": List<dynamic>.from(player.map((x) => x.toJson())),
};
}
class Player {
Player({
this.name,
this.rol,
});
String name;
String rol;
factory Player.fromJson(Map<String, dynamic> json) => Player(
name: json["name"],
rol: json["rol"],
);
Map<String, dynamic> toJson() => {
"name": name,
"rol": rol,
};
}
Then in your function call:
...updateUserData(UserData.toJson());
This is a tool that can help you with your model classes in this case https://app.quicktype.io/

how flutter map in for widget

my json=
{
"result": {
"name": "json1",
"pages": [{
"zones": [{
"title": "title1"
},
{
"title": "title2"
}],
"id": 4
},
{
"zones": [{
"title": "title3"
},
{
"title": "title4"
}],
"id": 12
}],
"creatorUserName": "admin",
"id": 2
}
}
futurebuilder code
List post = snapshot.data["result"]["pages"];
return new Stack(
children: post.where((val) => val["id"] == 4).map((post) {
for (var item in post['zones']) {
print("title "+ item['title']);
Container(
child: Text(item["title"]),
); //Container
}
}).toList(),
); //Stack
Error code: Stack's children must not contain any null values, but a null value was found at index 0
enter image description here
help how can to build an algorithms
if get id = 4 zones -> Text(title1), Text(title2),
else id empty zones -> Text(title1), Text(title2), zones -> Text(title3), Text(title4),
Try
List post = snapshots.data["result"]["pages"];
First Make a model class for your JSON response using this amazing webpage, after that you can easily. call the needed data
import 'dart:convert';
YourModelClassName yourModelClassNameFromJson(String str) => YourModelClassName.fromJson(json.decode(str));
String yourModelClassNameToJson(YourModelClassName data) => json.encode(data.toJson());
class YourModelClassName {
Result result;
YourModelClassName({
this.result,
});
factory YourModelClassName.fromJson(Map<String, dynamic> json) => YourModelClassName(
result: Result.fromJson(json["result"]),
);
Map<String, dynamic> toJson() => {
"result": result.toJson(),
};
}
class Result {
String name;
List<Page> pages;
String creatorUserName;
int id;
Result({
this.name,
this.pages,
this.creatorUserName,
this.id,
});
factory Result.fromJson(Map<String, dynamic> json) => Result(
name: json["name"],
pages: List<Page>.from(json["pages"].map((x) => Page.fromJson(x))),
creatorUserName: json["creatorUserName"],
id: json["id"],
);
Map<String, dynamic> toJson() => {
"name": name,
"pages": List<dynamic>.from(pages.map((x) => x.toJson())),
"creatorUserName": creatorUserName,
"id": id,
};
}
class Page {
List<Zone> zones;
int id;
Page({
this.zones,
this.id,
});
factory Page.fromJson(Map<String, dynamic> json) => Page(
zones: List<Zone>.from(json["zones"].map((x) => Zone.fromJson(x))),
id: json["id"],
);
Map<String, dynamic> toJson() => {
"zones": List<dynamic>.from(zones.map((x) => x.toJson())),
"id": id,
};
}
class Zone {
String title;
Zone({
this.title,
});
factory Zone.fromJson(Map<String, dynamic> json) => Zone(
title: json["title"],
);
Map<String, dynamic> toJson() => {
"title": title,
};
}