Dart\Flutter Model Relationship from Json Data - json

I have two json files that I retrieved via an api. I want to create a relationship between the product and the category for display in my product listview the name of the category instead of the id of the category.
here i have an example of my first json file which contains all the products.
listing.json
[
{
"id":1461267313,
"category_id":4,
"title":"Statue homme",
"description":"...",
"price":140.00,
"images_url":{
"small":"...",
"thumb":"..."
},
"creation_date":"2019-11-05T15:56:59+0000",
"is_urgent":false
},
{
"id":1691247255,
"category_id":8,
"title":"Pc portable hp elitebook 820 g1 core i5 4 go ram 250 go hdd",
"description":"...",
"price":199.00,
"images_url":{
"small":"...",
"thumb":"..."
},
"creation_date":"2019-10-16T17:10:20+0000",
"is_urgent":false
},
]
and there the second json file which contains the categories
categories.json
[
{
"id": 1,
"name": "VĂ©hicule"
},
//from 1 to 11
{
"id": 11,
"name": "Enfants"
}
]
I created a product model and a category model
product.dart
class Product {
int? id;
int? categoryId;
String? title;
String? description;
double? price;
ImagesUrl? imagesUrl;
String? creationDate;
bool? isUrgent;
Product(
{this.id,
this.categoryId,
this.title,
this.description,
this.price,
this.imagesUrl,
this.creationDate,
this.isUrgent});
}
category.dart
class Category {
int? id;
String? name;
Category({this.id, this.name});
}

create a new class ProductItem. After converting json file add both product & category in an order to the new class.
class ProductItem { final Product product; final Category category; ProductItem({required this.product, required this.category}); }

Finally, I created a map to match the category id of my product to the name field of my class category. I get it back with the key like that. productByCat return type is Map<int, String>.
for (int i = 0; i < dataProduct!.length; i++) {
for (int y = 0; y < dataCategory!.length; y++) {
if (dataProduct?[i]['category_id'] == dataCategory?[y]['id']) {
productByCat[dataProduct?[i]['category_id']] = dataCategory?[y]['name'];
}
}
}
return productByCat;

Related

Fetch data inside factory in flutter

I have a json response of this type
{
"uuid": "c6514be0-cced-43b7-b1f4-e66256c1dcaf",
"title": "Harry Potter",
"author": "6637e87b-c2ce-4774-b812-4e8a09312a40",
}
this answer is associated with another one through the author key
{
"author": "6637e87b-c2ce-4774-b812-4e8a09312a40",
"name": "J.K. Rowling",
}
So i have a Book class for first response
class Book {
final String uuid;
final String title;
final Author author;
Book({
required this.uuid,
required this.title,
required this.author,
});
}
and an Author class for second response
class Author {
final String uuid;
final String name;
Book({
required this.uuid,
required this.name,
});
}
My question is if there is a method to directly fetch the author during the book factory.
I tried with this method but i can't wait for response:
factory Book.fromJson(Map<String, dynamic> json) {
return Book(
uuid: json['uuid'],
title: json['title'],
author: fetchAuthor(json['author']),
);
}
Where
Future<Author> fetchAuthor(authorUuid) async {
http.Response author = await http.get(
Uri.parse(apiURLAuthors + authorUuid),
);
if (author.statusCode == 200) {
return Author.fromJson(jsonDecode(utf8.decode(author.bodyBytes)));
} else {
throw Exception("Failed to load author $authorUuid");
}
}
I'm not sure but you can call 2 model class(book & author) in another class where you wanted to show. Then create a function to call both the data from these 2 modal class and put it in global variable. Now you can able to access the data of both modal class globally. If you want to create list then you set all values in list variable else you can also create different data type values and save data of that particular index

How to get value from Json List - flutter

I have this code where i get json data into a list in flutter but i don't really know how to get the particular data i want like the value
main.dart
Future<String> loadDataFromJson() async {
return await rootBundle.loadString("assets/categories.json");
}
Future loadData() async {
String jString = await loadDataFromJson();
final jRes = json.decode(jString) as List;
List<Category> datas = jRes.map((e) => Category.fromJson(e)).toList();
print(datas);
}
#override
void initState() {
super.initState();
loadData();
}
Here I printed the data and it gave me this I/flutter ( 6111): [Instance of 'Category', Instance of 'Category', Instance of 'Category', Instance of 'Category']
Models
class Category {
final String catId;
final String catName;
Category({this.catId, this.catName});
factory Category.fromJson(Map<String, dynamic> json) {
return Category(catId: json['cat_id'], catName: json['category']);
}
}
my json is something like this but there are multiple
{
"category": "Design & Creativity",
"cat_id": "1",
"cat_suncategory": [
{
"sub_name": "Ads",
"sub_image": "https://images.unsplash.com/photo-1589838017489-9198a27bd040?ixid=MXwxMjA3fDB8MHxzZWFyY2h8Mnx8YWR2ZXJ0aXNlbWVudHxlbnwwfHwwfA%3D%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60"
}
]
}
So please how do i get the value i want
I cannot understand your problem but this may help you;
If your json values in 'jRes', you can do
String myCategory = jRes["category"];
String subName = jRes["cat_suncategory"][0]["sub_name"];
String subImage = jRes["cat_suncategory"][0]["sub_image"];
Because of using '[0]' is; the 'cat_suncategory' is an array and you should take first element of it, it means [0].

Android Kotlin parsing nested JSON

I'm still pretty new to programming with Kotlin but I can't seem to figure out the correct way to parse my JSON. I'm attempting to get "title" and "body" from "notification" in "unackd" array only.
So far I've got:
private fun parse(): Boolean {
try {
val ja = JSONArray(jsonData)
var jo: JSONObject
users.clear()
var user: User
for (i in 0 until ja.length()) {
jo = ja.getJSONObject(i)
val name = jo.getString("title")
val username = jo.getString("body")
user = User(username,name)
users.add(user)
}
return true
} catch (e: JSONException) {
e.printStackTrace()
return false
}
}
Meanwhile my JSON is structured as so:
{
"unackd": [
{
"notification": {
"title": "Title Test Number 200",
"body": "passage local they water difficulty tank industry allow increase itself captured strike immediately type phrase driver change save potatoes stems addition behavior grain trap rapidly love refused way television bright 1100"
},
"data": {
"id": "1100",
"phone": "+15555551234"
}
},
{
"notification": {
"title": "Title Test Number 199",
"body": "announced beside well noted mysterious farm he essential likely deeply vast touch 1099"
},
"data": {
"id": "1099",
"phone": "+15555551234"
}
}
],
"ackd": [
{
"notification": {
"title": "Title Test Number 200",
"body": "passage local they water difficulty tank industry allow increase itself captured strike immediately type phrase driver change save potatoes stems addition behavior grain trap rapidly love refused way television bright 1100"
},
"data": {
"id": "1100",
"phone": "+15555551234"
}
},
{
"notification": {
"title": "Title Test Number 199",
"body": "announced beside well noted mysterious farm he essential likely deeply vast touch 1099"
},
"data": {
"id": "1099",
"phone": "+15555551234"
}
}
]
}
I believe my issue is getting into "notification" to then get the strings "title" and "body". Which I've tried
test1 = jo.getJSONObject("notification")
Any help would be appreciated!
EDIT:
This is my logcat error, I assume it has to do with the JSON.typeMismatch:
at org.json.JSON.typeMismatch(JSON.java:111)
at org.json.JSONArray.<init>(JSONArray.java:96)
at org.json.JSONArray.<init>(JSONArray.java:108)
at android.os.AsyncTask$2.call(AsyncTask.java:333)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)
The exception message suggests that you're passing data that doesn't represent a JSON array when instantiating JSONArray:
at org.json.JSON.typeMismatch(JSON.java:111)
at org.json.JSONArray.<init>(JSONArray.java:96)
The JSON you've attached is in fact a JSON object, notice that its content is enclosed in {}. Hence to access the "unackd" array, you need to first create a JSON object, and then reference the array inside of it:
val root = JSONObject(jsonData)
val ja = root.getJSONArray("unackd")
// the rest of your code goes here
Listen friend , parsing the JSON Object with JSON ARRAY with key (like: unackd , ackd) is so simple.
There are 2 ways:
1st Way)
Parse your JSON to Pojo schema
http://www.jsonschema2pojo.org/
public class Ackd {
#SerializedName("notification")
#Expose
private Notification_ notification;
#SerializedName("data")
#Expose
private Data_ data;
public Notification_ getNotification() {
return notification;
}
public void setNotification(Notification_ notification) {
this.notification = notification;
}
public Data_ getData() {
return data;
}
public void setData(Data_ data) {
this.data = data;
}
}
public class Data {
#SerializedName("id")
#Expose
private String id;
#SerializedName("phone")
#Expose
private String phone;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
No need to Make all class for parsing (like ackd (Json Array))
2nd Way)
You need to PARSE JSON array with name only unackd not ackd.
String jsonStr = sh.makeServiceCall(url);
JSONObject jsonObj = new JSONObject(jsonStr);
// Getting JSON Array node
JSONArray unA= jsonObj.getJSONArray("unackd");
for (int i = 0; i < unA.length(); i++)
{
JSONObject c = unA.getJSONObject(i);
String title= c.getString("title");
String body= c.getString("body");
}
Auto generate Data class
http://www.jsonschema2pojo.org/
I suppose that your class is named Response.java
Response object=new Gson().fromjson(jsonContentFile,Response.class);
Following data classes are generated for your JSON using https://json2kotlin.com
data class Json4Kotlin_Base (
val unackd : List<Unackd>,
val ackd : List<Ackd>
)
and
data class Data (
val id : Int,
val phone : Int
)
and
data class Notification (
val title : String,
val body : String
)
and
data class Ackd (
val notification : Notification,
val data : Data
)
and
data class Unackd (
val notification : Notification,
val data : Data
)
Here's a video that explains how to implement these when generated.

Mapping JSON into Class Objects

I am trying to map my JSON file into a class object, and then update the cards based on the newly received JSON.
My JSON structure is like this
{
"$class": "FirstCard",
"id": "1",
"description": "I am card number one",
"Role": "attack",
"score": 0,
"tag": [
"string"
],................}
my Class looks like this:
class CardInfo {
//Constructor
String id;
String description;
String role;
int score;
}
How can I map the values in my JSON file into the fields of objects created from CardInfo class?
Update
the following trial prints null at ci.description, does this mean the object was never created ?
const jsonCodec = const JsonCodec
_loadData() async {
var url = 'myJsonURL';
var httpClient = createHttpClient();
var response =await httpClient.get(url);
print ("response" + response.body);
Map cardInfo = jsonCodec.decode(response.body);
var ci = new CardInfo.fromJson(cardInfo);
print (ci.description); //prints null
}
Update2
Printing cardInfo gives the following:
{$class: FirstCard, id: 1, description: I am card number one,........}
Note that it resembles the original JSON but without the double quotes on string values.
class CardInfo {
//Constructor
String id;
String description;
String role;
int score;
CardInfo.fromJson(Map json) {
id = json['id'];
description = json['description'];
role = json['Role'];
score = json['score'];
}
}
var ci = new CardInfo.fromJson(myJson);
You can use source generation tools like https://github.com/dart-lang/source_gen https://pub.dartlang.org/packages/json_serializable to generate the serialization and deserialization code for you.
If you prefer using immutable classes https://pub.dartlang.org/packages/built_value is a good bet.
If you want to get your JSON from a url do as follows:
import 'dart:convert';
_toObject() async {
var url = 'YourJSONurl';
var httpClient = createHttpClient();
var response =await httpClient.get(url);
Map cardInfo = JSON.decode(response.body);
var ci = new CardInfo.fromJson(cardInfo);
}
Please refer to the main answer if you want to know how to setup your class so that your JSON fields can be mapped to it. It is very helpful.
I created some useful library for this using reflection called json_parser which is available at pub.
https://github.com/gi097/json_parser
You can add the following to your dependencies.yaml:
dependencies:
json_parser: 0.1.1
build_runner: 0.8.3
Then the json can be parsed using:
DataClass instance = JsonParser.parseJson<DataClass>(json);
Follow the README.md for more instructions.
The best solution I've found is this medium post
Which converts the Json to dart very easily
import 'package:json_annotation/json_annotation.dart';
part 'post_model.g.dart';
#JsonSerializable()
class PostModel {
int userId;
int id;
String title;
String body;
PostModel(this.userId, this.id, this.title, this.body);
factory PostModel.fromJson(Map<String, dynamic> json) => _$PostModelFromJson(json);
Map<String, dynamic> toJson() => _$PostModelToJson(this);
}
You can generate them if you don't want to create them manually.
Add dependecies to pubspec.yaml:
dependencies:
json_annotation: ^4.0.0
dev_dependencies:
build_it: ^0.2.5
json_serializable: ^4.0.2
Create configurtion file my_classes.yaml:
---
format:
name: build_it
generator:
name: build_it:json
---
checkNullSafety: true
classes:
- name: CardInfo
fields:
- { name: id, type: String? }
- { name: description, type: String? }
- { name: role, type: String?, jsonKey: { name: Role } }
- { name: score, type: int? }
- { name: tag, type: List<String>, jsonKey: { defaultValue: [] } }
Run build process:
dart run build_runner build
Generated code my_classes.g.dart:
// GENERATED CODE - DO NOT MODIFY BY HAND
import 'package:json_annotation/json_annotation.dart';
part 'my_classes.g.g.dart';
// **************************************************************************
// build_it: build_it:json
// **************************************************************************
#JsonSerializable()
class CardInfo {
CardInfo(
{this.id, this.description, this.role, this.score, required this.tag});
/// Creates an instance of 'CardInfo' from a JSON representation
factory CardInfo.fromJson(Map<String, dynamic> json) =>
_$CardInfoFromJson(json);
String? id;
String? description;
#JsonKey(name: 'Role')
String? role;
int? score;
#JsonKey(defaultValue: [])
List<String> tag;
/// Returns a JSON representation of the 'CardInfo' instance.
Map<String, dynamic> toJson() => _$CardInfoToJson(this);
}
Now you can use them.
this pkg can help you convert JSON to a class instance. https://www.npmjs.com/package/class-converter
import { property, toClass } from 'class-convert';
class UserModel {
#property('i')
id: number;
#property()
name: string;
}
const userRaw = {
i: 1234,
name: 'name',
};
// use toClass to convert plain object to class
const userModel = toClass(userRaw, UserModel);
// you will get a class, just like below one
{
id: 1234,
name: 'name',
}

Map<String, HashSet<String>> to JSON, & Pretty Print

I'm trying to make my dataset correspond to this example:
var family = [{
"name" : "Jason",
"age" : "24",
"gender" : "male"
},
{
"name" : "Kyle",
"age" : "21",
"gender" : "male"
}];
I have a Map<String, HashSet<String>> of Names and unique alpha-numeric values correponding to specific entities to which those names could refer, let's call these entry items "IDs".
So for instance, Fyodor Mikhailovich Dostoyevsky would perhaps be related to the ID Q626, because that's a very specific reference, there aren't many widely known figures with that name. Whereas, Bush might be attached to G027, Q290, and Q118, referencing perhaps the man, the beer, and the shrub, in no particular order.
It looks like this (the real one is much bigger):
[Rao=[Q7293658, , Q7293657, Q12953055, Q3531237, Q4178159, Q1138810, Q579515, Q3365064, Q7293664, Q1133815], Hani Durzy=[], Louise=[, Q1660645, Q130413, Q3215140, Q152779, Q233203, Q7871343, Q232402, Q82547, Q286488, Q156723, Q3263649, Q456386, Q233192, Q14714149, Q12125864, Q57669, Q168667, Q141410, Q166028], Reyna=[Q7573462, Q2892895, Q363257, Q151944, Q3740321, Q2857439, Q1453358, Q7319529, Q733716, Q16151941, Q7159448, Q5484172, Q6074271, Q1753185, Q7319532, Q5171205, Q3183869, Q1818527, Q251862, Q3840414, Q5271282, Q5606181]]
Using Jackson I tried like this:
Map<String, HashSet<String>> map = q_valMap;
mapper.writeValue(new File("JSON_Output/user.json"), map);
But this seems wrong, as my output was all jumbled together, i.e.
{"Rao":["Q7293658","","Q7293657","Q12953055","Q3531237","Q4178159","Q1138810","Q579515","Q3365064","Q7293664","Q1133815"],"Hani Durzy":[""],"Louise":["","Q1660645","Q130413","Q3215140","Q152779","Q233203","Q7871343","Q232402","Q82547","Q286488","Q156723","Q3263649","Q456386","Q233192","Q14714149","Q12125864","Q57669","Q168667","Q141410","Q166028"],"Reyna":["Q7573462","Q2892895","Q363257","Q151944","Q3740321","Q2857439","Q1453358","Q7319529","Q733716","Q16151941","Q7159448","Q5484172","Q6074271","Q1753185","Q7319532","Q5171205","Q3183869","Q1818527","Q251862","Q3840414","Q5271282","Q5606181"]}
Do I just have to populate this JSON object iteratively?
Like the example up top, I think it should look something like this, though what follows is only a pseudocodish characterization, which is to say, not exactly this but something similar:
{
key: "Rao"
value: ["Q7293658","","Q7293657","Q12953055","Q3531237","Q4178159","Q1138810","Q579515","Q3365064","Q7293664","Q1133815"]
key: "Hani Durzy"
value: [""]
key: "Louise"
value: ["","Q1660645","Q130413","Q3215140","Q152779","Q233203","Q7871343","Q232402","Q82547","Q286488","Q156723","Q3263649","Q456386","Q233192","Q14714149","Q12125864","Q57669","Q168667","Q141410","Q166028"]
key: "Reyna"
value: ["Q7573462","Q2892895","Q363257","Q151944","Q3740321","Q2857439","Q1453358","Q7319529","Q733716","Q16151941","Q7159448","Q5484172","Q6074271","Q1753185","Q7319532","Q5171205","Q3183869","Q1818527","Q251862","Q3840414","Q5271282","Q5606181"]
}
is that not right?
UPDATE
public class JsonMapFileExample
{
public static void map(Map<String, HashSet<String>> q_valMap )
{
ObjectMapper mapper = new ObjectMapper();
ArrayNode array = mapper.createArrayNode();
for ( Entry entry: q_valMap.entrySet() )
{
ObjectNode node = mapper.createObjectNode()
.put("name", entry.getKey())
.put("ids", entry.getValue());
array.add(node);
}
mapper.writeValue("/home/matthias/Workbench/SUTD/nytimes_corpus/wdtk-parent/wdtk-examples/JSON_Output/user.json", array);
}
}
class MyEntity
{
private String name;
Set<String> value; // use names that you want in the result JSON
//constructors
public MyEntity()
{
}
public MyEntity(String name)
{
this.name = name;
}
//getters
public String getName()
{
return this.name;
}
public Set<String> getValue()
{
return this.value;
}
//setters
public void setName(String name)
{
this.name = name;
}
public void setValue(Set<String> value)
{
this.value = value;
}
}
You could manually set the key names, something like:
ArrayNode array = mapper.createArrayNode();
for (Entry entry: yourMap.entries()) {
ObjectNode node = mapper.createObjectNode()
.put("name", entry.key())
.putPOJO("ids", entry.value());
array.add(node);
}
mapper.writeValue(file, array);
Alternatively, you could create a class for your data
class MyEntity {
String name;
Set<String> ids; // use names that you want in the JSON result
// getters, setters if necessary
}
Transform your data map into a list of MyEntity, then use Jackson ObjectMapper to create JSON like mapper.writeValue(file, listOfMyEntities), the output would be like
[
{
"name": "some name here",
"ids": ["id1", "id2", ...]
}
// more elements here
]
how about this:
String name_list_file = "/home/matthias/Workbench/SUTD/nytimes_corpus/NYTimesCorpus/2005/01/02/test/people_test.txt";
String single_name;
try (
// read in the original file, list of names, w/e
InputStream stream_for_name_list_file = new FileInputStream( name_list_file );
InputStreamReader stream_reader = new InputStreamReader( stream_for_name_list_file , Charset.forName("UTF-8"));
BufferedReader line_reader = new BufferedReader( stream_reader );
)
{
while (( single_name = line_reader.readLine() ) != null)
{
//replace this by a URL encoder
//String associated_alias = single_name.replace(' ', '+');
String associated_alias = URLEncoder.encode( single_name , "UTF-8");
String platonic_key = single_name;
System.out.println("now processing: " + platonic_key);
Wikidata_Q_Reader.getQ( platonic_key, associated_alias );
}
}
//print the struc
Wikidata_Q_Reader.print_data();
}