I have an object with a bigint property i want to encode to json string:
class Token {
Token(
{
this.name,
this.supply,
});
String? name;
BigInt? supply;
factory Token.fromJson(Map<String, dynamic> json) {
return Token(
name: json['name'],
supply: json['supply'] == null ? null : BigInt.parse(json['supply']),
);
}
Map<String, dynamic> toJson() => <String, dynamic>{
'name': name,
'supply': supply == null ? null : supply!.toString(),
};
}
I create a method to encode json to string...
String tokenToJson(Token data) => jsonEncode(data.toJson())
... but the format is not correct because i need a bigint in the format json and not a string:
the result i want:
{"name":"Token","supply":100000000000000,}
the result i obtain:
{"name":"Token","supply":"100000000000000",}
jsonEncode doesn't manage bigint type and i found on internet only solutions with a conversion of the bigint to a string type.
NB: Same issue with jsonDecode
Thx
use this simple method instead of BigInt use just "num"
import 'dart:convert';
void main() {
String data = '''{"name":"Token","supply":100000000000000}''';
print("supply: ${Token.fromJson(jsonDecode(data)).supply}");
}
class Token {
Token({
required this.name,
required this.supply,
});
late final String name;
late final num supply;
Token.fromJson(Map<String, dynamic> json){
name = json['name'];
supply = json['supply'];
}
Map<String, dynamic> toJson() {
final _data = <String, dynamic>{};
_data['name'] = name;
_data['supply'] = supply;
return _data;
}
}
Please check the following answer, instead of calling toString method on supply just call toInt method which will prevents the quotations and you will get the formatted json as expected
import 'dart:convert';
class Token {
Token(
{
this.name,
this.supply,
});
String? name;
BigInt? supply;
factory Token.fromJson(Map<String, dynamic> json) {
return Token(
name: json['name'],
supply: json['supply'] == null ? null :BigInt.from(json['supply']) ,
);
}
Map<String, dynamic> toJson() => <String, dynamic>{
'name': name,
'supply': supply == null ? null : supply!.toInt(),
};
String tokenToJson(Token data) => json.encode(data.toJson());
}
void main() {
Token token = Token(name: "token_one",supply : BigInt.parse("10000061234567"));
print(token.tokenToJson(token));
}
Output
{"name":"token_one","supply":10000061234567}
You don't need to parse, you can use from for convert int to BigInt
import 'dart:convert';
void main() {
String data = '''{"name":"Token","supply":100000000000000}''';
print(Token.fromJson(jsonDecode(data)).toJson());
}
class Token {
String? name;
double? supply;
Token({this.name, this.supply});
Token.fromJson(Map<String, dynamic> json) {
name = json['name'];
supply = json['supply'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['name'] = name;
data['supply'] = supply;
return data;
}
}
Related
I'm trying to deserialize a json file and create instances from it but whatever way I use, I end up stucked because of the dynamic type :
type '_Map<String, dynamic>' is not a subtype of type 'Map<String, int>'
Here's my model :
class Race {
final String name;
final Map<String, int> abilitiesUpdater;
const Race({
required this.name,
required this.abilitiesUpdater
});
static fromJson(json) => Race(name: json['name'], abilitiesUpdater: json['abilitiesUpdater']);
}
Here's how I'm trying to deserialize the json file :
class RacesApi {
static Future<List<Race>> getRacesLocally(BuildContext context) async {
final assetBundle = DefaultAssetBundle.of(context);
final String fileContent = await assetBundle.loadString('Assets/COC_Monstres/Races.json');
List<dynamic> parsedListJson = jsonDecode(fileContent);
List<Race> racesList = List<Race>.from(parsedListJson.map<Race>((dynamic i) => Race.fromJson(i)));
return racesList;
}
}
Here's my json file :
[
{
"name": "Vampire",
"abilitiesUpdater": {
"DEX": 2,
"CHA": 2
}
},
{
"name": "Créature du lagon",
"abilitiesUpdater": {
"FOR": 2,
"CON": 2
}
},
...
]
How can I properly cast this json object to fit into my class ?
This works:
class Race {
final String name;
// changed to dynamic
final Map<String, dynamic> abilitiesUpdater;
const Race({required this.name, required this.abilitiesUpdater});
static fromJson(json) =>
Race(name: json['name'], abilitiesUpdater: json['abilitiesUpdater']);
}
Maybe after get the object you can parse that dynamic into int if you need it.
Change your Model Class to this:
class Race {
Race({
required this.name,
required this.abilitiesUpdater,
});
late final String name;
late final AbilitiesUpdater abilitiesUpdater;
Race.fromJson(Map<String, dynamic> json){
name = json['name'];
abilitiesUpdater = AbilitiesUpdater.fromJson(json['abilitiesUpdater']);
}
Map<String, dynamic> toJson() {
final _data = <String, dynamic>{};
_data['name'] = name;
_data['abilitiesUpdater'] = abilitiesUpdater.toJson();
return _data;
}
}
class AbilitiesUpdater {
AbilitiesUpdater({
required this.FOR,
required this.CON,
});
late final int FOR;
late final int CON;
AbilitiesUpdater.fromJson(Map<String, dynamic> json){
FOR = json['FOR'];
CON = json['CON'];
}
Map<String, dynamic> toJson() {
final _data = <String, dynamic>{};
_data['FOR'] = FOR;
_data['CON'] = CON;
return _data;
}
}
you can cast the json['abilitiesUpdater'] as Map<String, int> because internally flutter will set it default as Map<String, dynamic>
Code
class Race {
final String name;
final Map<String, int> abilitiesUpdater;
const Race({
required this.name,
required this.abilitiesUpdater
});
static fromJson(json) => Race(name: json['name'], abilitiesUpdater: json['abilitiesUpdater']) as Map<String,int>;
}
it is working fine with me i tried it here is the link to the code https://dartpad.dev/?id=550918b56987552eb3d631ce8cb9e063.
If you still getting error you can try this
class Race {
final String name;
final Map<String, int> abilitiesUpdater;
Race({
required this.name,
required this.abilitiesUpdater
});
static fromJson(json) => Race(name: json['name'], abilitiesUpdater: (json['abilitiesUpdater']as Map<String,int>)) ;
}
or you can try this
class Race {
final String name;
final Map<String, int> abilitiesUpdater;
const Race({required this.name, required this.abilitiesUpdater});
static fromJson(json) => Race(
name: json['name'],
abilitiesUpdater: json['abilitiesUpdater']
.map((key, value) => MapEntry<String, int>(key, value as int)),
);
}
Edit : To have something a little bit more handy and scalable, I created an extension, and it works fine eventhough I have to cast twice the object...
My model :
// import my extension
class Race {
Race({
required this.name,
required this.abilitiesUpdater,
});
late final String name;
late final Map<String, int> abilitiesUpdater;
// late final AbilitiesUpdater abilitiesUpdater;
Race.fromJson(Map<String, dynamic> json){
name = json['name'];
abilitiesUpdater = (json['abilitiesUpdater'] as Map<String, dynamic>).parseToStringInt();
}
}
My extension :
extension Casting on Map<String, dynamic> {
Map<String, int> parseToStringInt() {
final Map<String, int> map = {};
forEach((key, value) {
int? testInt = int.tryParse(value.toString());
if (testInt != null) {
map[key] = testInt;
} else {
debugPrint("$value can't be parsed to int");
}
});
return map;
}
}
Once again, any help on cleaning this is appreciated !
Original answer :
Thanks to Sanket Patel's answer, I ended up with a few changes that made my code works. However I'm pretty clueless on why I can't directly cast a
Map<String, dynamic>
object into a
Map<String, int>
one.
Any info on this would be appreciated :)
Here's how I changed my model class in the end :
class Race {
Race({
required this.name,
required this.abilitiesUpdater,
});
late final String name;
late final AbilitiesUpdater abilitiesUpdater;
Race.fromJson(Map<String, dynamic> json){
name = json['name'];
abilitiesUpdater = AbilitiesUpdater.fromJson(json['abilitiesUpdater']);
}
}
class AbilitiesUpdater {
final Map<String, int> abilitiesUpdater = {};
AbilitiesUpdater.fromJson(Map<String, dynamic> json){
json.forEach((key, value) {
abilitiesUpdater[key] = int.parse(value.toString());
});
}
}
I'm trying to get the nested values from my locally stored json file with Flutter.
I can get the "outer" values, but I haven't been able to get the "inner" ones. I have googled and searched here, but I still can't make it work, so any help is much appreciated.
I put the code in a sandbox to make it easier to see.
https://codesandbox.io/s/loving-thunder-meklbc?file=/lib/main.dart
If you rather look here this is what some files look like:
json:
[{
"id":184423,
"created":"2022-11-18T09:32:56.000Z",
"raw_data":[
{"measurement_id":18,"index":0,"substance":655,"pressure":20,"temperature":30.03},
{"measurement_id":18,"index":1,"substance":648,"pressure":38,"temperature":30.03},
{"measurement_id":18,"index":2,"substance":636,"pressure":90,"temperature":30.02},
{"measurement_id":18,"index":3,"substance":623,"pressure":130,"temperature":30.05},
{"measurement_id":18,"index":4,"substance":598,"pressure":147,"temperature":29.99}
]
},
{
"id":184423,
"created":"2022-11-19T09:32:56.000Z",
"raw_data":[
{"measurement_id":19,"index":0,"substance":586,"pressure":160,"temperature":30.05},
{"measurement_id":19,"index":1,"substance":564,"pressure":170,"temperature":29.99},
{"measurement_id":19,"index":2,"substance":553,"pressure":173,"temperature":30},
{"measurement_id":19,"index":3,"substance":544,"pressure":162,"temperature":30.02},
{"measurement_id":19,"index":4,"substance":538,"pressure":164,"temperature":30.01}
]
}
]
handler:
import 'dart:convert';
import 'package:flutter/services.dart' as rootbundle;
import '../model/usermodel.dart';
Future<List<UserModel>> readJsonData() async {
final jsondata = await rootbundle.rootBundle.loadString('/userdata.json');
final list = json.decode(jsondata) as List<dynamic>;
//print(list);
return list.map((e) => UserModel.fromJson(e)).toList();
}
model:
// ignore_for_file: non_constant_identifier_names
class UserModel {
late int? id, measurementId, index, substance, pressure;
late double? temperature;
UserModel(
this.id,
this.measurementId,
this.index,
this.substance,
this.pressure,
this.temperature,
);
UserModel.fromJson(Map<String, dynamic> json) {
id = json["id"];
measurementId = json['measurement_id'];
index = json['index'];
substance = json['substance'];
pressure = json['pressure'];
temperature = json['temperature'];
}
}
class UserModel {
UserModel(this.id, this.raw_data);
/// Creates a UserModel from Json map
factory UserModel.fromJson(Map<String, dynamic> json) => UserModel(
json['id'] as int?,
(json['raw_data'] as List<dynamic>?)
?.map((e) => Data.fromJson(e as Map<String, dynamic>))
.toList(),
);
final int? id;
final List<Data>? raw_data;
}
//Data
class Data {
Data(
this.measurement_id,
this.index,
this.substance,
this.pressure,
this.temperature,
);
final int? measurement_id;
final int? index;
final int? substance;
final int? pressure;
final double? temperature;
/// Creates a Data from Json map
factory Data.fromJson(Map<String, dynamic> json) => Data(
json['measurement_id'] as int?,
json['index'] as int?,
json['substance'] as int?,
json['pressure'] as int?,
(json['temperature'] as num?)?.toDouble(),
);
}
List<UserModel> models = [];
for (var item in list) {
models.addAll(item.map((e) => UserModel.fromJson(e['id'], e['raw_data'])));
}
return models;
UserModel.fromJson(int id, Map<String, dynamic> json) {
this.id = id; // parse json (raw_data)
}
Did this according to this manual
https://www.bezkoder.com/dart-flutter-parse-json-string-array-to-object-list/
Dart/Flutter parse array of JSON objects into List
JSON that comes from the server
{"myChannels":[{"id":"2","name":"channel2test","imageUrl":"image1.png"},{"id":"2","name":"channel2test","imageUrl":"image2.png"}]}
Model Class
class ChannelModel {
String channelID;
String channelName;
String imageUrl;
ChannelModel(this.channelID, this.channelName, this.imageUrl);
factory ChannelModel.parsingChannels(dynamic json) {
return ChannelModel(json['channelID'] as String,
json['channelName'] as String, json['imageUrl'] as String);
}
#override
String toString() {
return '{ ${this.channelID}, ${this.channelName}, ${this.imageUrl} }';
}
}
Main block
try {
final response = await http.post(
url,
body: json.encode({
'action': 'getMyChannels',
'userID': userID,
'returnSecureToken': true,
}),
);
// print(jsonDecode(response.body));
var extractedData =
jsonDecode(response.body)['myChannels'] as List<dynamic>;
List<ChannelModel> channelObjects = extractedData
.map((cJson) => ChannelModel.parsingChannels(cJson))
.toList();
print(channelObjects);
channelObjects.forEach((Data) {
print('test');
});
the results is the following...
print(channelObjects) > outputs > []
print('test') > not working , channelObjects not looping
I would suggest serializing your response to dart classes. It would be much easier to access the data you want.
class ApiResponse {
ApiResponse({
required this.myChannels,
});
List<MyChannel> myChannels;
factory ApiResponse.fromJson(Map<String, dynamic> json) => ApiResponse(
myChannels: List<MyChannel>.from(
json["myChannels"].map((x) => MyChannel.fromJson(x)),
),
);
}
class MyChannel {
MyChannel({
required this.id,
required this.name,
required this.imageUrl,
});
String id;
String name;
String imageUrl;
factory MyChannel.fromJson(Map<String, dynamic> json) => MyChannel(
id: json["id"],
name: json["name"],
imageUrl: json["imageUrl"],
);
}
Then you can use it this way :
final extractedData = ApiResponse.fromJson(json.decode(response.body) as Map<String, dynamic>);
And access the data you want
extractedData.myChannels[0].id
extractedData.myChannels[0].name
extractedData.myChannels[0].imageUrl
for (var ch in extractedData.myChannels){
print(ch.id);
print(ch.name);
print(ch.imageUrl);
}
part 'example.g.dart';
#JsonSerializable()
class Channel{
final String id;
final String name;
final String? imageUrl;
Channel({required this.id, required this.name, this.imageUrl});
factory Channel.fromJson(Map<String, dynamic> json) => _$ChannelFromJson(json);
Map<String, dynamic> toJson() => _$ChannelToJson(this);
}
#JsonSerializable()
class ChannelList{
final List<Channel> myChannels;
ChannelList({required this.myChannels});
factory ChannelList.fromJson(Map<String, dynamic> json) => _$ChannelListFromJson(json);
Map<String, dynamic> toJson() => _$ChannelListToJson(this);
}
final extractedData = ChannelList.fromJson(json.decode(response.body));
https://pub.dev/packages/json_serializable
Using JsonSerializable more useful and understandable. You can read documentation of that package
I have a base class like:
class TransportationVehicle {
String name;
TransportationVehicle(this.name);
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['name'] = name;
return data;
}
}
And multiple sub-classes like:
class Bike extends TransportationVehicle {
int pedals;
Bike(String name, this.pedals) : super(name);
#override
Map<String, dynamic> toJson() {
final data = super.toJson();
data['pedals'] = pedals;
return data;
}
}
With that, I can transform a list of different types into a json string. But how would that work with fromJson functionality?
You can use the same idea from the toJson() method by using the base class.
import 'dart:convert';
class TransportationVehicle {
final String? name;
TransportationVehicle({
this.name,
});
factory TransportationVehicle.fromRawJson(String str) =>
TransportationVehicle.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory TransportationVehicle.fromJson(dynamic json) => TransportationVehicle(
name: json['name'] == null ? null : json['name'] as String,
);
Map<String, dynamic> toJson() => {
'name': name == null ? null : name,
};
}
class Bike extends TransportationVehicle {
final int? pedals;
Bike({
String? name,
this.pedals,
}) : super(name: name);
factory Bike.fromRawJson(String str) => Bike.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory Bike.fromJson(dynamic json) {
TransportationVehicle vehicle = TransportationVehicle.fromJson(json);
return Bike(
name: vehicle.name == null ? null : vehicle.name,
pedals: json['pedals'] == null ? null : json['pedals'] as int,
);
}
Map<String, dynamic> toJson() {
final data = super.toJson();
data['pedals'] = pedals == null ? null : pedals;
return data;
}
}
Kindly assist.
I am attempting to create a model using the JSON to Dart tool https://app.quicktype.io/
The aim is to retrieve a list of all companies (with their properties) from a JSON API.
I am getting the below errors:
the argument type 'dynamic' can't be assigned to the parameter type Map<String, dynamic>
the argument type 'dynamic' can't be assigned to the parameter type Iterable
the argument type 'dynamic' can't be assigned to the parameter type Int
Please refer to the image below.
the argument type 'dynamic' can't be assigned to the parameter type...
Thank you.
I have tested this class and it works without errors
import 'dart:convert';
CompanyModel companyModelFromJson(String str) => CompanyModel.fromJson(json.decode(str));
String companyModelToJson(CompanyModel data) => json.encode(data.toJson());
class CompanyModel {
CompanyModel({
this.companies,
});
List<Company> companies;
factory CompanyModel.fromJson(Map<String, dynamic> json) => CompanyModel(
companies: List<Company>.from(json["companies"].map((x) => Company.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"companies": List<dynamic>.from(companies.map((x) => x.toJson())),
};
}
class Company {
Company({
this.id,
this.name,
});
int id;
String name;
factory Company.fromJson(Map<String, dynamic> json) => Company(
id: json["id"],
name: json["name"],
);
Map<String, dynamic> toJson() => {
"id": id,
"name": name,
};
}
As alternative you can use this code from JsonToDart
class CompanyModel {
List<Companies> companies;
CompanyModel({this.companies});
CompanyModel.fromJson(Map<String, dynamic> json) {
if (json['companies'] != null) {
companies = new List<Companies>();
json['companies'].forEach((v) {
companies.add(new Companies.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.companies != null) {
data['companies'] = this.companies.map((v) => v.toJson()).toList();
}
return data;
}
}
class Companies {
int id;
String name;
Companies({this.id, this.name});
Companies.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['name'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['name'] = this.name;
return data;
}
}