Cast Complex JSON Dart - json

the dart code below allows you to decode a json that comes from a backend inside resultValue, I have the response of the rest call with the json shown below, when I go to create the list with the values I have the following error, to what is due? how do i fix it?
JSON Link
Error:
//Line: return data.map((jsonObject) => new Manutenzione(
flutter: Errore: type 'List<String>'
is not a subtype of type 'String' in type cast
Dart code:
var urlmod = await Storage.leggi("URL") + "/services/rest/v3/processes/PreventiveMaint/instances";
final resultValue = await apiRequest(Uri.parse(urlmod), {}, UrlRequest.GET, true);
Map<String, dynamic> map = json.decode(resultValue);
List<dynamic> data = map["data"];
try {
return data
.map((jsonObject) => new Manutenzione(
["_id"] as String,
["_user"] as String,
["__user_description"] as String,
["Description"] as String,
["ShortDescr"] as String,
["_Site_description"] as String,
["_Team_description"] as String,
["_status_description"] as String,
["_Company_description"] as String,
))
.toList();
} catch (err) {
print("Errore: " + err.toString());
}
return List.empty();
}
JSON:
{
...
data: [
{
_id: value1,
_user: value2,
..
},
{
_id: value1,
_user: value2,
..
},
]
}

You forgot to specify jsonObject before the square brackets.
var urlmod = await Storage.leggi("URL") + "/services/rest/v3/processes/PreventiveMaint/instances";
final resultValue = await apiRequest(Uri.parse(urlmod), {}, UrlRequest.GET, true);
Map<String, dynamic> map = json.decode(resultValue);
List<dynamic> data = map["data"];
try {
return data
.map((jsonObject) => new Manutenzione(
jsonObject["_id"] as String,
jsonObject["_user"] as String,
jsonObject["__user_description"] as String,
jsonObject["Description"] as String,
jsonObject["ShortDescr"] as String,
jsonObject["_Site_description"] as String,
jsonObject["_Team_description"] as String,
jsonObject["_status_description"] as String,
jsonObject["_Company_description"] as String,
))
.toList();
} catch (err) {
print("Errore: " + err.toString());
}
return List.empty();
}

Related

How can i convert a JSON String to List<String> in flutter?

I`m trying to retrieve the content of a table from oracle apex to my flutter app with http.get method, and atribute the values to a class i created. Problem is that 3 of the atributes of this class need to be List, so, when i try to map it, it returns this error: [ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: type 'String' is not a subtype of type 'List' in type cast.
this is the JSON:
{
"items": [
{
"id": "1",
"nome": "Feijão Tropeiro",
"id_dia_da_semana": "seg",
"id_categoria": "ga",
"url_da_imagem": "https://live.staticflickr.com/65535/52180505297_2c23a61620_q.jpg",
"ingredientes": "vários nadas"
}
],
and this is the class:
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'dart:convert';
class Meal {
final String id;
final String descricao;
final List<String> ingredients;
final List<String> idDiaSem;
final List<String> idCategory;
final String imageUrl;
const Meal({
required this.id,
required this.descricao,
required this.ingredients,
required this.idDiaSem,
required this.idCategory,
required this.imageUrl,
});
Map<String, dynamic> toMap() {
return <String, dynamic>{
'id': id,
'nome': descricao,
'ingredientes': ingredients,
'id_dia_da_semana': idDiaSem,
'id_categoria': idCategory,
'url_da_imagem': imageUrl,
};
}
factory Meal.fromMap(Map<String, dynamic> map) {
return Meal(
id: map['id'] as String,
descricao: map['nome'] as String,
ingredients: map['ingredientes'] as List<String>,
idDiaSem: map['id_dia_da_semana'] as List<String>,
idCategory: map['id_categoria'] as List<String>,
imageUrl: map['url_da_imagem'] as String,
);
}
String toJson() => json.encode(toMap());
factory Meal.fromJson(String source) =>
Meal.fromMap(json.decode(source) as Map<String, dynamic>);
}
can anyone help me please to fix this error? i`ve tried to convert it unsuccessfully
When you have a string you want to parse to a list, there should be a separator. For example, let's suppose this strings:
// The separator here is a comma with a space, like ', '
String str1 = 'ingredient1, ingredient2, bread, idunno, etc';
// The separator here is a simple space, ' '
String str2 = 'ingredient1 ingredient2 bread idunno etc';
Once you identified the separator in the string, you may want to use the string split method in dart, specifying the separator. For example:
// Separator is a simple comma with no spaces, ','
String str1 = 'ingredient1,ingredient2,bread,idunno,etc';
// Splits the string into array by the separator
List<String> strList = str1.split(',');
// strList = ['ingredient1', 'ingredient2', 'bread', 'idunno', 'etc'];
More information on the split dart method at https://api.dart.dev/stable/2.14.4/dart-core/String/split.html
EDIT: Example with your code, supposing the property ingredients is a string that represents an array of strings, separated with ",":
factory Meal.fromMap(Map<String, dynamic> map) {
return Meal(
id: map['id'] as String,
descricao: map['nome'] as String,
ingredients: (map['ingredientes'] as String).split(','),
// ...
You can't cast them to List<String> because they simply aren't a list. If you want them to be a List with a single element you could do this instead:
ingredients: [map['ingredientes'] as String],
idDiaSem: [map['id_dia_da_semana'] as String],
idCategory: [map['id_categoria'] as String],
or make sure the JSON has them as list like
{
"items": [
{
"id": "1",
"nome": "Feijão Tropeiro",
"id_dia_da_semana": ["seg"],
"id_categoria": ["ga"],
"url_da_imagem": "https://live.staticflickr.com/65535/52180505297_2c23a61620_q.jpg",
"ingredientes": ["vários nadas"]
}
],
try this:
static List<Meal> fromMap(Map<String, dynamic> map) {
List<Meal> result = [];
for(var item in map['items']){
result.add(Meal(
id: item['id'] as String,
descricao: item['nome'] as String,
ingredients: item['ingredientes'] as String,
idDiaSem: item['id_dia_da_semana'] as String,
idCategory: item['id_categoria'] as String,
imageUrl: item['url_da_imagem'] as String,
))
}
return result;
}

How to access JSON nested data in flutter dart

I have the below json data, wherein I want to access the values inside the feeling_percentage.
{
"status": "200",
"data": {
"feeling_percentage": {
"Happy": "0",
"Sad": "0",
"Energetic": "0",
"Calm": "0",
"Angry": "0",
"Bored": "0"
},
}
}
I am able to fetch it using the below API code
Future<List<Data>> makePostRequest() async {
List<Data> list = [];
final uri = Uri.parse('<api>');
final headers = {'Content-Type': 'application/json', 'X-Api-Key':'<api_key>'};
Map<String, dynamic> body = {'user_id': 3206161992, 'feeling_date': '15-04-2022'};
String jsonBody = json.encode(body);
final encoding = Encoding.getByName('utf-8');
Response response = await post(
uri,
headers: headers,
body: jsonBody,
encoding: encoding,
);
int statusCode = response.statusCode;
String responseBody = response.body;
print('response body'+ responseBody);
}
After reading few articles, still not able to figure out how do I access the percentage of happy, sad inside the feeling_percentage.
I have created the model as
class Data{
FeelingPercentage feelingPercentage;
Data(
{required this.feelingPercentage});
factory Data.fromJson(Map<String, dynamic> json) {
return Data(
feelingPercentage: FeelingPercentage.fromJson(json["data"]),
);
}
}
class FeelingPercentage {
String? happy;
String? sad;
String? energetic;
String? calm;
String? angry;
String? bored;
FeelingPercentage({this.happy, this.sad, this.energetic, this.calm, this.angry, this.bored});
factory FeelingPercentage.fromJson(Map<String, dynamic> json) {
return FeelingPercentage(
happy: json["happy"] as String,
sad: json["sad"] as String,
energetic: json["energetic"] as String,
calm: json["calm"] as String,
angry: json["angry"] as String,
bored: json["bored"] as String,
);
}
}
Another way:
import 'package:fast_json/fast_json_selector.dart' as parser;
void main() {
final path = '{}.data.{}.feeling_percentage';
final level = path.split('.').length;
void select(parser.JsonSelectorEvent event) {
final levels = event.levels;
if (levels.length == level && levels.join('.') == path) {
print(event.lastValue);
event.lastValue = null;
}
}
parser.parse(_source, select: select);
}
const _source = '''
{
"status": "200",
"data": {
"feeling_percentage": {
"Happy": "0",
"Sad": "0",
"Energetic": "0",
"Calm": "0",
"Angry": "0",
"Bored": "0"
}
}
}''';
Output:
{Happy: 0, Sad: 0, Energetic: 0, Calm: 0, Angry: 0, Bored: 0}
You can use this website to convert your JSON object to a dart class.
it automatically creates the fromJson function, which can be used to pass JSON and receive the Dart objects.
Change this line in your model feelingPercentage: FeelingPercentage.fromJson(json["data"]), to feelingPercentage: FeelingPercentage.fromJson(json["data"]["feeling_percentage"]),
This will fix your issue.
You can do a JSON decode that will will result in a map, and then do the assigned like you are doing on your from Json factory, but as another constructor instead:
Class
Todo.fromMap(Map map) :
this.title = map['title'],
this.completed = map['completed'];
In use
Todo.fromMap(json.decode(item))
First decode response.body, then create FeelingPercentage object from json["data"]["feeling_percentage"] map.
Future<FeelingPercentage> makePostRequest() async {
...
final json = json.decode(response.body);
return FeelingPercentage.fromJson(json["data"]["feeling_percentage"])
}
class FeelingPercentage {
String? happy;
String? sad;
String? energetic;
String? calm;
String? angry;
String? bored;
FeelingPercentage({this.happy, this.sad, this.energetic, this.calm, this.angry, this.bored});
factory FeelingPercentage.fromJson(Map<String, dynamic> json) {
return FeelingPercentage(
happy: json["Happy"] as String,
sad: json["Sad"] as String,
energetic: json["Energetic"] as String,
calm: json["Calm"] as String,
angry: json["Angry"] as String,
bored: json["Bored"] as String,
);
}
}

fetch user data from server flutter

I'm following this tutorial from devs docs to fetch data from internet but I can't decode response to User object.
Since I'm using Postman to check API I can tell you that my request is successfully received and server responses me with 200 and a body full of data (name, id and token) but when I try to call fromJson method inside try-catch block to create User object it fails and this error is printed :
flutter: Response 200
flutter: type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'String'
This is my User class :
class User extends Equatable {
final String token;
final String name;
final String id;
const User({
required this.token,
required this.name,
required this.id,
});
static const User empty = User(token: "token", name: "name", id: "id");
Map<String, dynamic> toMap() {
return <String, String>{
'token': token,
'name': name,
'id': id,
};
}
factory User.fromMap(Map<String, dynamic> json) {
return User(
token: json['token'] ?? "token",
name: json['name'] ?? "name",
id: json['id'] ?? "id",
);
}
String toJson() => json.encode(toMap());
factory User.fromJson(Map<String, dynamic> jsonMap) => User.fromMap(jsonMap);
#override
String toString() {
return token + ' ' + name + ' ' + id + '\n';
}
#override
List<Object?> get props => [token, name, id];
}
UserCredentials that's just a wrapper for username and password :
class UserCredentials {
final String name;
final String email;
final String password;
UserCredentials(
{required this.name, required this.email, required this.password});
factory UserCredentials.fromJson(Map<String, dynamic> json) {
return UserCredentials(
name: json['name'] as String,
email: json['email'] as String,
password: json['password'] as String,
);
}
Map<String, String> toJsonRegistration() {
return {
"name": name,
"email": email,
"password": password,
};
}
Map<String, String> toJsonLogin() {
return {
"email": email,
"password": password,
};
}
#override
String toString() {
return name + " " + email + " " + password + '\n';
}
}
And this is my user_repository function used to get data from server :
Future<User> _login(UserCredentials user) async {
User? userFetched;
//print(user);
http.Response response = await http.post(
Uri.parse("http://link_to_repo"),
body: user.toJsonLogin(),
);
print("Inizio");
print((response.body));
print(jsonDecode(response.body));
print(User.fromJson(jsonDecode(response.body)));
print("fine");
if (response.statusCode == 200) {
print(response.statusCode);
try {
userFetched = User.fromJson(jsonDecode(response.body));
print(userFetched);
} catch (e) {
print(e);
}
print("End");
return userFetched!;
} else {
print("Login Failure from repository");
throw Exception("Email already taken");
}
}
As you seen above it's able to print "Response 200" but not to complete successfully the operation inside try-catch block.
Edit :
This is the response.body :
{"data" : {"token":"50|IUMNqKgc7Vffmz8elRd0MIZeSyuEgHL418KwQ0Jz","name":"test","id":1}}
And jsonDecode(response.body)) :
{data: {token: 50|IUMNqKgc7Vffmz8elRd0MIZeSyuEgHL418KwQ0Jz, name: test, id: 1}}
Solution :
This post is a little confusing but to be clear :
Clucera gave me the exact solution to fetch the data and create User object so I accepted its answers.
Josip Domazet's answer helped me fixing the error but he didn't solve the problem because I still couldn't create User data.
Looking at your code it looks like you are doing the following
User.fromJson(jsonDecode(response.body));
and from there you are creating the User instance with the following factory
factory User.fromMap(Map<String, dynamic> json) {
return User(
token: json['token'] ?? "token",
name: json['name'] ?? "name",
id: json['id'] ?? "id",
);
The issue is that your Json is contained in another json called "data" as your print response show
{data: {token: 50|IUMNqKgc7Vffmz8elRd0MIZeSyuEgHL418KwQ0Jz, name: test, id: 1}}
in this case you have two solution, either you nest the keys inside your constructor (don't suggest you this approach)
factory User.fromMap(Map<String, dynamic> json) {
return User(
token: json['data']['token'] ?? "token",
name: json['data']['name'] ?? "name",
id: json['data']['id'] ?? "id",
);
Or where you parse the json you can extract directly the data json (I suggest you this option)
User.fromJson(jsonDecode(response.body)['data']);
jsonDecode(response.body) will return a Map. However your constructor User.fromJson takes a String as argument. Decoding it once is enough and from then on your can work with the Map you already have. So no need to call jsonDecode again in fromJson, this should work fine:
factory User.fromJson(Map<String, dynamic> jsonMap) =>
User.fromMap(jsonMap);
If we look at your exception it tell us just that:
flutter: type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'String'
Your constructor expects a String but received a Map (_InternalLinkedHashMap).

decode stored json result string in shared preferences

When the app launch it triggers an API call and in my case, I want to store the response data for later use, so I used shared preferences for that and stored response data as a string. now I want to properly decode the data to use, from the stored string from shared preferences.
here is how I covert the data to string,
SharedPreferences prefs = await SharedPreferences.getInstance();
Response response = await _dio.post(
_baseUrl,
data: {"index": indexNum, "password": password},
options: Options(contentType: Headers.formUrlEncodedContentType),
);
if (response.statusCode == 200) {
var result = response.data;
//convert result data to string
var resultData = Result.encode(result);
// store the resultData in shared_preferences
prefs.setString('results', resultData);
}
encode method,
class Result {
Result({
required this.table,
required this.data,
});
String table;
List<Data> data;
factory Result.fromJson(Map<String, dynamic> json) => Result(
table: json["table"],
data: List<Data>.from(json["data"].map((x) => Data.fromJson(x))),
);
//encode method
static String encode(List<dynamic> results) => json.encode(
results.map((result) => result.toString()).toList(),
);
}
here is my approach to decode data from string,
getData() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String? resultData = prefs.getString('results');
List<dynamic> decodedJson = jsonDecode(resultData!);
print(decodedJson);
}
resultData string,
resultData string after decode,
I am new to flutter and what I want is the proper way to decode this data from models. Below are my model classes.
import 'dart:convert';
class Result {
Result({
required this.table,
required this.data,
});
String table;
List<Data> data;
factory Result.fromJson(Map<String, dynamic> json) => Result(
table: json["table"],
data: List<Data>.from(json["data"].map((x) => Data.fromJson(x))),
);
static String encode(List<dynamic> results) => json.encode(
results.map((result) => result.toString()).toList(),
);
}
class Data {
Data({
required this.subjectName,
required this.year,
required this.credits,
required this.sOrder,
required this.result,
required this.onlineAssignmentResult,
});
String subjectName;
String year;
String credits;
String sOrder;
String result;
String onlineAssignmentResult;
factory Data.fromJson(json) => Data(
subjectName: json["subject_name"],
year: json["year"],
credits: json["credits"],
sOrder: json["s_order"],
result: json["result"],
onlineAssignmentResult: json["online_assignment_result"],
);
}
Appreciate your time and help.
Your JSON is in the wrong syntax for Flutter to decode with jsonDecode()
All strings and variable names need to be enclosed in " or '
I.e. {subject_name: should be {"subject_name":

Obtaining Map<String, Element> rather than Map<dynamic, dynamic>

We start with a class Element for a member of the periodic table.
import 'dart:convert' as JSON;
class Element {
String name;
Element({this.name = ""});
String toString() {
return this.name.toString();
}
}
We can then decode a JSON string
void f1() {
var jsonStr = """{ "Na": { "name": "Sodium" }, "Ca": { "name": "Calcium" } }""";
final json = JSON.jsonDecode(jsonStr);
print(json.runtimeType); // MappedListIterable<dynamic, dynamic>
final elements = json.map((key, value) => MapEntry(key, Element(name: value['name'])));
print(elements.runtimeType); // _InternalLinkedHashMap<dynamic, dynamic>
}
but suppose we want to specify the type of the result:
Map<String, Element> f3() {
var jsonStr = """{ "Na": { "name": "Sodium" }, "Ca": { "name": "Calcium" } }""";
final json = JSON.jsonDecode(jsonStr);
final elements = Map<String, Element>.fromIterable(json,
key: (k, v) => k,
value: (k, v) => Element.fromJson(name: v['name'])
);
return elements;
}
How can I get around the following error?
Error: The argument type 'String Function(dynamic, dynamic)' can't be assigned
to the parameter type 'String Function(dynamic)?'.
to ensure that the returned object is of type Map<String, Element>?
The signature for Map<K, V>.fromIterable is:
Map<K, V>.fromIterable(
Iterable iterable,
{K key(
dynamic element
)?,
V value(
dynamic element
)?}
)
Note that key: and value: both take functions of only one argument. The idea for key is to take an element from your iterable, and make a Key out of it - in your case, a String. Then for the value callback, you take the same element and make a Value out of it - in your case, an Element.
Also, a map is not iterable, but Map.entries is, so you need to iterate through json.entries, instead of just json.
So something like the following should get the job done:
final elements = Map<String, Element>.fromIterable(json.entries,
key: (entry) => entry.key,
value: (entry) => Element(name: entry.value['name']),
);