Using Flutter Freezed to generate code to parse a Json Object - json

I'm trying to parse some JSON from a file and decided to use Freezed to generate the code. The problem is that (as far as i can tell) there's no way to use a JSON object's name.
So say I have the following JSON object:
{
"uniqueName":{
"website": "https://www.example.com/",
"description": "Some description",
"hosted_demo": false,
"demo": "",
"oss": false,
"source": "",
"other-links": [
{
"title": "Clients",
"site": "https://shlink.io/apps"
}
],
"license": "MIT"
}
}
Then this would be the required dart code for Freezed code (done with instructions from this site):
// 1. import freezed_annotation
import 'package:freezed_annotation/freezed_annotation.dart';
// import any other models we depend on
import 'otherLinks.dart';
// 2. add 'part' files
part 'freezed_files/item.freezed.dart';
part 'generated/item.g.dart';
// 3. add #freezed annotation
#freezed
// 4. define a class with a mixin
class Item with _$Item {
// 5. define a factory constructor
factory Item(
{
// 6. list all the arguments/properties
#Default("") String website,
#Default("") String description,
// ignore: invalid_annotation_target
#Default(false) #JsonKey(name: 'hosted_demo') bool? hostedDemo,
#Default("") String demo,
#Default(false) bool oss,
#Default("") String source,
// ignore: invalid_annotation_target
#Default([]) #JsonKey(name: 'other-links') List<OtherLinks> otherLinks,
#Default("") String license
// 7. assign it with the `_Item` class constructor
}) = _Item;
// 8. define another factory constructor to parse from json
factory Item.fromJson(Map<String, dynamic> json) => _$ItemFromJson(json);
}
But i have no idea how to get the uniqueName into the data class. Most other places I've checked assume that the JSON data is formatted with the uniqueName inside JSON object with its own key. While refactoring the JSON file is an option, I would rather not. The whole JSON file is about 12000 lines, making refactoring it a pain.
Do you folks have any idea how I can get uniqueName into the data class?

I'm not sure if this what you're looking for, but how about this?
import 'package:freezed_annotation/freezed_annotation.dart';
import 'otherLinks.dart';
part 'freezed_files/item.freezed.dart';
part 'generated/item.g.dart';
#freezed
class Item with _$Item {
factory Item({
// Add a new property to save the uniqueName
#Default("") String uniqueName,
#Default("") String website,
#Default("") String description,
#Default(false) #JsonKey(name: 'hosted_demo') bool? hostedDemo,
#Default("") String demo,
#Default(false) bool oss,
#Default("") String source,
#Default([]) #JsonKey(name: 'other-links') List<OtherLinks> otherLinks,
#Default("") String license
}) = _Item;
factory Item.fromJson(Map<String, dynamic> json) => _$ItemFromJson(json);
// Add this new function
factory Item.fromUniqueJson(Map<String, dynamic> json) {
// Get the uniqueName string key and save it
var uniqueNameKey = json.keys.first;
// Convert the rest of the json object beneath the uniqueName key
return Item.fromJson(json[uniqueNameKey])
// Return the new Item with the uniqueName saved as a property
.copyWith(uniqueName: uniqueNameKey);
}
}

import 'package:freezed_annotation/freezed_annotation.dart';
part 'item.freezed.dart';
part 'item.g.dart';
#freezed
class Item with _$Item {
factory Item({
#Default(UniqueName) UniqueName uniqueName,
}) = _Item;
factory Item.fromJson(Map<String, dynamic> json) => _$ItemFromJson(json);
}
#freezed
class UniqueName with _$UniqueName {
factory UniqueName({
#Default('') String website,
#Default('') String description,
#Default(false) bool hostedDemo,
#Default('') String demo,
#Default(false) bool oss,
#Default('') String source,
#Default([]) #JsonKey(name: 'other-links') List<OtherLink> otherLinks,
#Default('') String license,
}) = _UniqueName;
factory UniqueName.fromJson(Map<String, dynamic> json) =>
_$UniqueNameFromJson(json);
}
#freezed
class OtherLink with _$OtherLink {
factory OtherLink({
#Default('') String title,
#Default('') String site,
}) = _OtherLink;
factory OtherLink.fromJson(Map<String, dynamic> json) =>
_$OtherLinkFromJson(json);
}

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);

Getting type 'List<dynamic>' is not a subtype of type 'Map<String, dynamic>'error in JSON

Im sure you know the problem above. Im wondering how I can solve it. I understand that my data is in form of a list but inside the data class I used map. I don't really understand how I should change it to work, basically I just followed the flutter.dev documentation
So if you are wondering what I did
I basically parsed my data with json_serializable. In testing with test data all worked fine.
My data:
My model contains a title, image & a nested class called modelData.
`import 'package:json_annotation/json_annotation.dart';
import 'modelData.dart';
part 'Modell.g.dart';
#JsonSerializable(explicitToJson: true)
class Modell {
final String title;
final String image;
final ModelData modelData;
Modell(this.title, this.image, this.modelData);
factory Modell.fromJson(Map<String, dynamic> json)
=> _$ModellFromJson(json);
Map<String, dynamic> toJson() => _$ModellToJson(this);}
`
import 'package:json_annotation/json_annotation.dart';
part 'modelData.g.dart';
#JsonSerializable()
class ModelData {
final String title;
ModelData(this.title);
factory ModelData.fromJson(Map<String, dynamic> json)
=> _$ModelDataFromJson(json);
Map<String, dynamic> toJson() => _$ModelDataToJson(this);
}
Im consuming the data with this code:
var modelle = const[];
Future loadDataList() async {
String content = await rootBundle.loadString("assets/ddddddd.json");
List collection = json.decode(content);
List<Modell> _modelle = collection.map((json) => Modell.fromJson(json)).toList();
setState(() {
modelle = _modelle;
});
}
void initState() {
loadDataList();
super.initState();
& if needed here a part of my Data:
[
{
"title":" Alfa Romeo ",
"image":" AlfaRomeo.png ",
"modelData":[
{
"title":" 4C ",
"variantenData":[
]
},
I hope I wrote clear & detailed enough. If Im missing something, sry
-----Update-----
I tested a bit & found out that with simply adding List I no longer get the error, will test further to see whether the solution really works as intended
import 'package:json_annotation/json_annotation.dart';
import 'modelData.dart';
part 'Modell.g.dart';
#JsonSerializable(explicitToJson: true)
class Modell {
final String title;
final String image;
List <ModelData> modelData; //adding List
Modell(this.title, this.image, this.modelData);
factory Modell.fromJson(Map<String, dynamic> json)
=> _$ModellFromJson(json);
Map<String, dynamic> toJson() => _$ModellToJson(this);
}
You have parsed the data and all but the class named Modell should contain a list of ModelData and not a single ModelData. Please change the type to a list of ModelData and it should work hopefully.
class Modell {
final String title;
final String image;
final List<ModelData> modelDataList;
Modell(this.title, this.image, this.modelDataList);
factory Modell.fromJson(Map<String, dynamic> json)
=> _$ModellFromJson(json);
Map<String, dynamic> toJson() => _$ModellToJson(this);}```
In this part:
var modelle = const[];
Future loadDataList() async {
String content = await rootBundle.loadString("assets/ddddddd.json");
List collection = json.decode(content);
List<Modell> _modelle = collection.map((json) => Modell.fromJson(json)).toList();
setState(() {
modelle = _modelle;
});
}
void initState() {
loadDataList();
super.initState();
More specific here:
List collection = json.decode(content);
If you go to Flutter Example will see that collection will return a Map<String, dynamic>.
Try change to:
Map<String, dynamic> collection = json.decode(content);

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

Dart json serialization, how to deal with _id from mongodb being private in Dart?

I'm using automatic serialization/deserialization in dart like mentioned here
import 'package:json_annotation/json_annotation.dart';
part 'billing.g.dart';
#JsonSerializable()
class Billing {
Billing(){}
String _id;
String name;
String status;
double value;
String expiration;
factory Billing.fromJson(Map<String, dynamic> json) => _$BillingFromJson(json);
Map<String, dynamic> toJson() => _$BillingToJson(this);
}
But in order for the serialization/deserialization to work, the fields must be public. However, in Dart, a field with _ at the beggining is private. So I can't use _id from mongodb to serialize/deserialize things.
How can I overcome this?
You can use #JsonKey annotation. Refer https://pub.dev/documentation/json_annotation/latest/json_annotation/JsonKey/name.html
import 'package:json_annotation/json_annotation.dart';
part 'billing.g.dart';
#JsonSerializable()
class Billing {
Billing(){}
// Tell json_serializable that "_id" should be
// mapped to this property.
#JsonKey(name: '_id')
String id;
String name;
String status;
double value;
String expiration;
factory Billing.fromJson(Map<String, dynamic> json) => _$BillingFromJson(json);
Map<String, dynamic> toJson() => _$BillingToJson(this);
}

Parse json array without names in Dart

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/