I am trying to get the JSON response from the server and output it to the console.
Future<String> login() async {
var response = await http.get(
Uri.encodeFull("https://etrans.herokuapp.com/test/2"),
headers: {"Accept": "application/json"});
this.setState(() {
data = json.decode(response.body);
});
print(data[0].name);
return "Success!";
}
Unhandled Exception: type '_InternalLinkedHashMap<String, dynamic>' is
not a subtype of type 'List
What could be the reason?
Here are 2 common ways this could go wrong:
If your response is a json array like
[
{
key1: value1,
key2: value2,
key3: value3,
},
{
key1: value1,
key2: value2,
key3: value3,
},
.....
]
Then, we use data[0]["name"], not data[0].name
Unless we cast to an object that has the name property, we cannot use data[0].name
We cast like this data = json.decode(response.body).cast<ObjectName>();
ObjectName can be whatever object you want (Inbuilt or Custom). But make sure it has the name property
If your response is a JSON object like
{
dataKey: [
{
key1: value1,
key2: value2,
key3: value3,
}
]
}
Then json.decode will return a Map, not a List
Map<String, dynamic> map = json.decode(response.body);
List<dynamic> data = map["dataKey"];
print(data[0]["name"]);
You can use
new Map<String, dynamic>.from(snapshot.value);
Easiest way (one dimensional):
Map<String, dynamic> data = new Map<String, dynamic>.from(json.decode(response.body));
print(data['name']);
You are trying to case an Instance of InternalLinkedHashMap which is not possible.
You should Serialize and deserialize it back to Map<String, dynamic>.
InternalLinkedHashMap<String, dynamic> invalidMap;
final validMap =
json.decode(json.encode(invalidMap)) as Map<String, dynamic>;
You have to convert the runtimeType of data from _InternalLinkedHashMap to an actual List.
One way is to use the List.from.
final _data = List<dynamic>.from(
data.map<dynamic>(
(dynamic item) => item,
),
);
If you need work with generic fields has a workaround:
class DicData
{
int tot;
List<Map<String, dynamic>> fields;
DicData({
this.tot,
this.fields
});
factory DicData.fromJson(Map<String, dynamic> parsedJson) {
return DicData(
tot: parsedJson['tot'],
//The magic....
fields : parsedJson["fields"] = (parsedJson['fields'] as List)
?.map((e) => e == null ? null : Map<String, dynamic>.from(e))
?.toList()
);
}
}
You can get this error if you are using retrofit.dart and declare the wrong return type for your annotated methods:
#GET("/search")
Future<List<SearchResults>> getResults();
// wrong! search results contains a List but the actual type returned by that endpoint is SearchResults
vs
#GET("/search")
Future<SearchResults> getResults();
// correct for this endpoint - SearchResults is a composite with field for the list of the actual results
This worked for me:
Create a List Data
Use Map to decode the JSON file
Use the List object Data to fetch the name of the JSON files
With the help of index and the list object I have printed the items dynamically from the JSON file
setState(){
Map<String, dynamic> map = json.decode(response.body);
Data = map["name"];
}
// for printing
Data[index]['name1'].toString(),
Seems like this error could pop up depending on various developer faults.
In my case, I was using an EasyLocalization key but without defining it under asset/lang/en_US.json file.
If your working with Firebase Cloud,make sure that you're not trying to add multiple data with same DocumentID;
firestore.collection('user').document(UNIQUEID).setData(educandos[0].toJson()).
To convert from _InternalLinkedHashMap<String, dynamic> to Map<String, double> I used
Map<String,double>.from(json['rates'])
I had the same error using json_annotation, json_serializable, build_runner. It occurs when calling the ClassName.fromJson() method for a class that had a class property (example: class User has a property class Address).
As a solution, I modified the generated *.g.dart files of each class, by changing Map<String, dynamic>) to Map<dynamic, dynamic>) in everywhere there is a deep conversion inside the method _$*FromJson
The only problem is that you have to change it again every time you regenerate your files.
Related
Can someone help me to figure out, how to get the uid from my table?
When the user selects a row, then onSelect: onSelected is getting used.
This returns the selected row and the values (as example: true {uid: 1xorAjA7hRZfOdN3zpkAWI7spgp1, username: awdwa,...} - true means the row is selected, false the row is not selected)
Now I want to get the uid, so the first value of the Map<String, dynamic>.
My first step is to store all data in a variable: var selectedUid = userTable.onSelected, and then I need to get access to the Map<String, dynamic> to get the uid right?
But how can I get acess to the first value of Map<String, dynamic> when I have a (bool, Map <String, dynamic>)? Someone have an advice how I can do this?
Sorry, when this is a dumb question, but the (bool, Map <String, dynamic>) confuses me completly. Thank you a lot for your help.
code onSelected from table:
List<Map<String, dynamic>> selecteds = [];
onSelected(bool value, Map <String, dynamic> item){
print("$value $item ");
if (value) {
selecteds.add(item);
} else {
selecteds.removeAt(selecteds.indexOf(item));
}
notifyListeners();
}
Edit:
When I try to get the uid from the bool, Map<String, Dynamic> like this:
selectedId = userTable.getSelected,
print('Uid: '+selectedId[uid])
I get this error:
The following NoSuchMethodError was thrown while handling a gesture:
'[]'
Dynamic call of null.
Receiver: Instance of '(bool, Map<String, String>) => dynamic'
Arguments: ["M0glOQKUwagZJGOyzVEU1JJgQo23"]
When I try to safe the data in List<Map<String, dynamic>> and just try to get the first value, then I get the error:
Expected a value of type 'List<Map<String, dynamic>>', but got one of type '(bool, Map<String, dynamic>) => List<Map<String, dynamic>>'
code:
getSelected(bool value, Map <String, dynamic> item){
print("$value $item ");
if (value) {
selecteds.add(item);
return selecteds as List<Map<String, dynamic>>;
} else {
selecteds.removeAt(selecteds.indexOf(item));
}
notifyListeners();
}
Maps are not ordered. There is no "first" item. You probably meant to ask how to get the "uid" from the map?
You can use item["uid"].
I have a json response from a server and the format is as follows....
{
key1: {
subKey1: value1
subKey2: value2
[...]
},
key2: {
[...]
},
[...]
}
All the answers I've come accross suggest mapping directly to PODOs with predefined Model classes with fromJson(...).
However, this JSON is for translation strings and is gigantic. top level keys are language codes, but these can be hundreds of entries, and the sub level keys are in the hundreds as well, and their names may change at any time, etc.
Isnt there a simple way to go from Map<String, dynamic> which jsonDecode(response.body) gives me to Map<String, Map<String,String>> ?
I've tried doing
Map<String, Map<String, String> typedMap = jsonResponse.map((key, value) => MapEntry(key, value))
but I'm told the formats don't match.
Here's an edited output based on suggestions,
Full sample code first... Get.find<> is from the GetX package for state management. It works just fine in other areas of the project.
class TranslationsService {
final logger = getLogger('Translation Service');
Future<Map<String, Map<String, String>>> getTranslations() async {
var response = await http.get(
[url]);
if (response.statusCode == HttpStatus.ok) {
var jsonResponse =
convert.json.decode(response.body) as Map<String, dynamic>;
Map<String, Map<String, String>> result = jsonResponse
.map((key, value) => MapEntry(key, value as Map<String, String>));
logger.i(result);
return result;
} else {
logger.e('Request failed with status code ${response.statusCode}');
return null;
}
}
static Future load() async {
final api = TranslationsService();
Map<String, Map<String, String>> map = await api.getTranslations();
Get.find<TranslatedStrings>().map = map;
}
}
And the output, which is even more error filled now...
E/flutter (26806): [ERROR:flutter/lib/ui/ui_dart_state.cc(186)] Unhandled Exception: type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'Map<String, String>' in type cast
E/flutter (26806): #0 TranslationsService.getTranslations.<anonymous closure>
package:dream_x/services/translations_service.dart:19
E/flutter (26806): #1 MapMixin.map (dart:collection/maps.dart:170:28)
E/flutter (26806): #2 TranslationsService.getTranslations
package:dream_x/services/translations_service.dart:19
E/flutter (26806): <asynchronous suspension>
[....]
I/example.dream_(26806): Waiting for a blocking GC ProfileSaver
I might be stupid here, but it seems overly complex to convert a simple map..... :D
And, just as proof that the response I'm getting is not some fluke, here's the full output of a print of jsonResponse with a temporary truncated file, formated and validated with JSON Formatter:
{
"en":{
"title":"Title English",
"label_search":"Search",
"label_profile":"Profile",
"label_dashboard":"Dashboard"
},
"fr":{
"title":"Title French",
"label_search":"Recherche",
"label_profile":"Profil",
"label_dashboard":"Tableau de bord"
}
}
Since you are sure they will always be string, you can use value.toString()
Map<String, Map<String, String> typedMap = jsonResponse.map((key, value) => MapEntry(key, value.toString()))
Problem
You were on the right track by using jsonResponse.map for the most part, except that you misunderstood what the map callback returns.
jsonResponse.map((key, value) => MapEntry(key, value)
The key here is your top level key. It's going to change like "key1", "key2" ...
The value here is your Map<dynamic,dynamic> that is in front of the key. This is what it essentially holds:
//Dart is parsing this as Map<dynamic, dynamic> probably
{
subkey1: value1,
subKey2: value2
}
Solution
All you need to do is cast the Map<dynamic,dynamic> to Map<String,String> using the as keyword.
Map<String,Map<String,String>> result = jsonResponse.map(
(key, value) => MapEntry(key,value as Map<String,String>)
);
Update
Casting can be done using any of these two methods
Map<T1,T2>.from, where T1 and T2 are your target types:
MapEntry(key, Map<String, String>.from(value))
Map.castFrom<S1,S2,T1,T2>, where S1 and S2 are your source types and T1 and T2 are your target types:
MapEntry(key, Map.castFrom<String, dynamic, String, String>(value))
Output
Printing runtime types:
print("${jsonResponse.runtimeType}");
print("${result.runtimeType}");
This is what it prints
JsLinkedHashMap<String, dynamic> //<-- jsonResponse
JsLinkedHashMap<String, Map<String, String>> //<-- result
This might stem from a misunderstanding on my part where I'm too used to Javascript that can read JSON outright and does not need to explicitly convert it to an interface of known properties in advance.
As such, I have decided to proceed differently. I have used QuickType to get the boiler plate code based on a reduced data set and I added the known properties to the boilerplate afterwards. When properties are added, they will be added directly to the object structure.
Not optimal, but we don't want to fight too much for this.
I am new to flutter, so I honestly don't know the why I am receiving this error.
List < BaseResponse > pEShippingDetail = [];
Future loadMessageList() async {
http.Response response = await http.get('xxxxx');
//await Future.delayed(Duration(seconds: 3));
String content = response.body;
List collection = json.decode(content);
List < BaseResponse > _messages = collection.map((json) => BaseResponse.fromJson(json)).toList();
setState(() {
pEShippingDetail = _messages;
});
}
void initState() {
loadMessageList();
super.initState();
}
Your json.decode(content); produced a _InternalLinkedHashMap<String, dynamic> but you are try to assign it to a List of type dynamic(default type).
To solve this, first see what is the data format of the response is. Then use required type. You could use final without static type but that's not the best option here. Map<String, dynamic> should work but cannot explicitly say it is correct without looking at the json response.
That get request is returning a JSON object, not a list. JSON objects are decoded to Map<String, dynamic>. So the exception is because you are trying to assign a Map<String, dynamic> to a List variable, which cannot be done.
Looking at the response above though, perhaps you mean to use the categories property in the response, not the entire response?
Have a closer look at the response, and decide which parts of the data you are actually interested in.
I am using same model to parse 2 json responses,
In one response an attribute user is string type, and in the other response user is an object.
How could I parse in this situation? I tried,
CampaignProductDetails.fromJson(Map<String, dynamic> json) {
user= json['user'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['user'] = this.user;
return data;
}
But it shows _typeError when user is an object. How should I sort it out? Do I need to create a new model for this single attribute?
You can use is operator in Dart
CampaignProductDetails.fromJson(Map<String, dynamic> json) {
user= json['user'] == null ? null : (json['user'] is String ? json['user'] : this.user;
}
as an alternative, In Dart every object has a runtimeType instance member which returns type of object at runtime ( I wouldn't advice to use it on production, somewhere read that it is only for debugging purpose).
Im setting up firebase cloud messaging and in my onResume() callback I have the following:
Future<void> onResume(Map<String, dynamic> message) async {
final Map<String,dynamic> data = message['data'];
final String url = data['url'];
if (url != null) {
_webViewController?.loadUrl(url);
}
}
When the function reaches
final Map<String,dynamic> data = message['data'];
it returns prematurely and silently without warnings.
If I instead run
final dynamic data = message['data'];
it continues as expected.
Inspecting the message type revels that message is InternalLinkedHashMap and cannot be cast too Map<String, dynamic>.
It says _InternalLinkedHashMap<dynamic, dynamic>' is not a subtype of type 'Map<String, dynamic>'.
How do I do this?
How can I find this issue in the future if it has no trace?
I found the best way to solve it were to use Map.from() and specify the variable type as Map:
final Map<String, dynamic> data = Map.from(message['data']);
Try this:
final Map<String,dynamic> data = Map.castFrom<dynamic, dynamic, String, dynamic>(message['data']);
You should only do this, of course, if all of your keys are really Strings.
If you want to understand what's going on, see this:
var x = {};
print(x.runtimeType);
Map<String, dynamic> y = Map.castFrom<dynamic, dynamic, String, dynamic>(x);
print(y.runtimeType);
You can try to map all keys to string. Something like:
final Map<String,dynamic> data = message.map((key, value) => MapEntry(key.toString(), value));