Parse json array without names in Dart - json

I cannot parse such json
[{"operation_id":"38911","external_id":null,"status":"SUCCESS","date":"2019-12-01T12:30:08.000Z","amount":200}]
The problem lies in array with dynamic names. Here's my POJO:
class PaymentHistoryResponse {
final List<History> list;
PaymentHistoryResponse({this.list});
}
class History {
final String operationId;
final dynamic externalId;
final String status;
final DateTime date;
final int amount;
History({
#required this.operationId,
#required this.externalId,
#required this.status,
#required this.date,
#required this.amount
});
factory History.fromJson(String str) => History.fromMap(json.decode(str));
String toJson() => json.encode(toMap());
factory History.fromMap(Map<String, dynamic> json) => History(
operationId: json["operation_id"],
externalId: json["external_id"],
status: json["status"],
date: DateTime.parse(json["date"]),
amount: json["amount"]
);
Map<String, dynamic> toMap() => {
"operation_id": operationId,
"external_id": externalId,
"status": status,
"date": date.toIso8601String(),
"amount": amount
};
}
I also receive other json containing arrays, but named ones and I was able to decode them. How can I convert this one? P.s I've also made some research through this site and found some quite similar questions but a bit different and it didn't help me.

Since this is an array and not just a JSON you will need to do something like this:
mList = List<UserModel>.from(response.data.map((i) => UserModel.fromJson(i)));
Hint: for generating models with toJson and fromJson use this website:
https://javiercbk.github.io/json_to_dart/

Related

FLUTTER- How to save a List<Object> into shared Preferences?

I want to add a product to cart and save it, so that when i open the app again, it is present in the cart. i can add multiple products to cart, so I am looking to save a List<Products>
I want to save a List into sharedPreferences and retrieve the same, but there are no methods for that. I tried using setStringList but I am unable to convert the string into object. And the data is not getting saved also.
my class model-
import 'dart:convert';
class Products {
Products({
required this.title,
required this.price,
required this.description,
required this.image,
this.quantity = 0,
});
final String title;
final double price;
final String description;
final String image;
int quantity;
factory Products.fromRawJson(String str) =>
Products.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory Products.fromJson(Map<String, dynamic> json) => Products(
title: json["title"],
price: json["price"].toDouble(),
description: json["description"],
image: json["image"],
);
Map<String, dynamic> toJson() => {
"title": title,
"price": price,
"description": description,
"image": image,
};
}
The shared_preferences library has only the options to save the following.
int
string
List
double
boolean
Reference:
https://pub.dev/documentation/shared_preferences/latest/shared_preferences/SharedPreferences-class.html
But what you could do is to create a List<String> in their jsonEncode form and save it.
Convert the List to List by encoding each of them using https://api.flutter.dev/flutter/dart-convert/jsonEncode.html
Once done you can save it and while decoding it similarly use jsonDecode
Hope this helps.
Thanks!
import 'dart:convert';
//first converts your array to json string store it in session
String strJsonString = json.encode(arrayProducts);
//save strJsonString as String into your session
//when you want to retrive it from session just decode session value
List<Products> = json.decode(strJsonString);

The unnamed constructor is already defined

I created a Post Model class using Dart and got this error saying "message": "The unnamed constructor is already defined.\nTry giving one of the constructors a name". Thsi is how my code is below:
final String caption;
final String comments;
final String datePosted;
final int likes;
Post({
required this.caption,
required this.comments,
required this.datePosted,
required this.likes,
});
factory Post(Map<String, dynamic> json) {
return Post(
caption: json['Caption'],
comments: json['Comments'],
datePosted: json['Date Posted'],
likes: json['Likes'],
);
}
}
Please help I'd really appreciate it
change to this
factory Post.fromJson(Map<String, dynamic> json) {
return Post(
caption: json['Caption'],
comments: json['Comments'],
datePosted: json['Date Posted'],
likes: json['Likes'],
);
}

Null-safety for fromJson like methods

I want to define a simple class model UserResponse in Flutter 2.0.5 and build a fromJson method attached to this class to create an instance easily after receiving the data from the backend in json format.
class UserResponse {
String name;
UserResponse ({
required this.name,
});
UserResponse.fromJson(Map<String, dynamic> json) {
name= json['name'].toString();
}
}
The dart compiler however throws an error here:
dart(not_initialized_non_nullable_instance_field)
Furthermore:
Non-nullable instance field 'name' must be initialized.
Try adding an initializer expression, or add a field initializer in this constructor, or mark it 'late'.
If I know that I will only call the fromJson method if I have all the required data, how should I create the new Instance in this method? I don't want to change the name field in the class to late.
Use a factory constructor.
class UserResponse {
final String name;
UserResponse({
required this.name,
});
factory UserResponse.fromJson(Map<String, dynamic> json) {
return UserResponse(name: json['name'].toString());
}
}
For null-safety. You need to be check null right way. And front-end need handle server don't return this key, we need mock data and sure app can't crash.
class UserResponse {
UserResponse({
this.name,
});
final String? name;
factory UserResponse.fromRawJson(String str) =>
UserResponse.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory UserResponse.fromJson(Map<String, dynamic> json) => UserResponse(
name: json["name"] == null ? null : json["name"].toString(),
);
Map<String, dynamic> toJson() => {
"name": name == null ? null : name,
};
}
According to this very similar question there are mainly to ways:
Use an initializer list for the method
Use a factory method
Thus,
UserResponse.fromJson(Map<String, dynamic> json) :
name= json['name'] as String;
or
factory UserResponse.fromJson(Map<String, dynamic> json) {
return UserResponse(
name: json['name'] as String,
);
}

JSON encoding in Dart

I have worked on decoding/encoding JSONs in my Flutter/Dart app. The decoding works just fine, but I have a very nasty problem when encoding my objects to JSON.
These are nested objects. Every one of them has its toJson and fromJson methods, in order to ensure that jsonEncode and Decode works. A small snippet of my work:
class App {
factory App.fromJson(Map<String, dynamic> json) => App(
langPref: json["langPref"],
langFallb: json["langFallb"],
users: List.of(json["users"]).map((i) => i).toList(),
);
String langPref;
String langFallb;
List<User> users;
/// JSON-Export
Map<String, dynamic> toJson() => {
"langPref": langPref,
"langFallb": langFallb,
"users": jsonEncode(users),
};
}
and the nested class:
class User {
int userid;
// actually there's more, including more nested objects
/// JSON-Import
factory User.fromJson(Map<String, dynamic> json) {
return User(
userid: int.parse(json["userid"]),
);
}
/// JSON-Export
Map<String, dynamic> toJson() {
return {
"userid": this.userid,
};
}
}
The problem is: When I encode the top level class "App", it correctly calls the toJson() method of the nested class. However, the corresponding JSON should read like this:
{
"langPref":"de-DE",
"langFallb":"en-GB",
"users":
[
{
"userid": 1
// and so on
It does, however, look like this:
{
"langPref":"de-DE",
"langFallb":"en-GB",
"users":"[{\"userid\":1
// and so on
So, the jsonEncode somehow introduces additional double quotes, which even makes sense somehow. It produces a String, and inside the JSON a string should be encoded .... But I guuess I'm just doing something wrong and missing something obvious .... How can I tell jsonEncode to accept the result of the operation, instead of encoding it as a string?
Can somebody help me?
This problem rises because you use jsonEncode() which return string object
you must use jsonDecode() that return a Map<String, dynamic>
and your App class will be like following
class App {
factory App.fromJson(Map<String, dynamic> json) => App(
langPref: json["langPref"],
langFallb: json["langFallb"],
users: List.of(json["users"]).map((i) => i).toList(),
);
String langPref;
String langFallb;
List<User> users;
/// JSON-Export
Map<String, dynamic> toJson() => {
"langPref": langPref,
"langFallb": langFallb,
"users": jsonEDecode(users),
};
}
Update
2nd method is to remove jsonEncode() without use jsonDecode()
3rd method use tojson() method in user class like following code
"users": users.map((user) => user.tojson()).toList(),
4th method the best method
use json_serializable library with json_annotation library to generate json serialization for annotated classes,
Flutter team approve this method as the best and the official one as described in Official Flutter Documentation.
app.dart
import 'package:json_annotation/json_annotation.dart';
part 'app.g.dart';
#JsonSerializable()
class App{
String langPref;
String langFallb;
List<User> users;
App({this.langPref, this.langFallb, this.users});
factory App.fromJson(Map<String, dynamic> json) => _$AppFromJson(json);
Map<String, dynamic> toJson() => _$AppToJson(this);
}
user.dart
import 'package:json_annotation/json_annotation.dart';
part 'user.g.dart';
#JsonSerializable()
class User{
int userId;
User({this.userId});
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
}
Great .... I will answer my own question. :-)
Further experiments lead to the following conclusion:
class App {
factory App.fromJson(Map<String, dynamic> json) => App(
langPref: json["langPref"],
langFallb: json["langFallb"],
users: List.of(json["users"]).map((i) => i).toList(),
);
String langPref;
String langFallb;
List<User> users;
/// JSON-Export
Map<String, dynamic> toJson() => {
"langPref": langPref,
"langFallb": langFallb,
"users": users,
};
}
New is only the last line .... I can directly pass the users list. It's not necessary to use jsonEncode for all of the nested objects and lists and maps etc.
Sorry for stealing the time of the readers, but maybe this answer will help others.

Access nested objects in json using json_serializable in Dart

Trying to convert my json to objects in Dart/Flutter using the json_serializable. I cannot seem to find a way to access a nested ID (data is coming from MongoDB thus the $ in the json).
Here is the json:
{
"_id": {
"$oid": "5c00b227" <-- this is what I am trying to access
},
"base": 1,
"tax": 1,
"minimum": 5,
"type": "blah"
}
Result:
class Thing {
final int id;
final String base;
final String tax;
final String type;
final int minimum;
}
It is not possible with json_serializable package itself. You have to create separate objects for getting this nested data.
Look the discussion here
https://github.com/google/json_serializable.dart/issues/490
But, there is possible way to get nested fields with added converter (solution was found here https://github.com/google/json_serializable.dart/blob/master/example/lib/nested_values_example.dart)
import 'package:json_annotation/json_annotation.dart';
part 'nested_values_example.g.dart';
/// An example work-around for
/// https://github.com/google/json_serializable.dart/issues/490
#JsonSerializable()
class NestedValueExample {
NestedValueExample(this.nestedValues);
factory NestedValueExample.fromJson(Map<String, dynamic> json) =>
_$NestedValueExampleFromJson(json);
#_NestedListConverter()
#JsonKey(name: 'root_items')
final List<String> nestedValues;
Map<String, dynamic> toJson() => _$NestedValueExampleToJson(this);
}
class _NestedListConverter
extends JsonConverter<List<String>, Map<String, dynamic>> {
const _NestedListConverter();
#override
List<String> fromJson(Map<String, dynamic> json) => [
for (var e in json['items'] as List)
(e as Map<String, dynamic>)['name'] as String
];
#override
Map<String, dynamic> toJson(List<String> object) => {
'items': [
for (var item in object) {'name': item}
]
};
}
try this,
class Thing {
int id;
String base;
String tax;
String type;
int minimum;
Thing({
this.id,
this.base,
this.tax,
this.type,
this.minimum,
});
factory Thing.fromJson(Map<String, dynamic> json) {
return Thing(
id: json['_id']["oid"],
base: json['base'].toString(),
tax: json['tax'].toString(),
type: json['type'].toString(),
minimum: json['minimum'],
);
}
}