Reputation: 35
I have an object called ShoppingListProduct which has an id (string), ticked (boolean), and also a product (product).
So, when I want to read the ShoppingListProduct from json.
class ShoppingListProduct extends Equatable {
ShoppingListProduct({
required this.ID,
required this.product,
required this.ticked,
});
final int ID;
final Product product;
late bool ticked;
ShoppingListProduct.fromJson(Map<String, dynamic> map)
: ID = (map['ID'] as int).toInt(),
product = Product.fromJson(map['product']),
ticked = (map['ticked'] as bool);
Map<String, dynamic> toJson() {
return {
'ID': ID,
'product': product,
'ticked': ticked,
};
}
@override
String toString() {
return 'ShoppingListProduct:\n\tID: $ID\n\tProduct: $product\n\tTicked: $ticked';
}
@override
List<Object> get props => [ID, product, ticked];
}
Here's the handler class which saves it to a local file.
class ShoppingListHandler {
ShoppingListHandler._privateConstructor();
static final ShoppingListHandler instance = ShoppingListHandler._privateConstructor();
static File? _file;
static const _fileName = 'shopping_list_file.txt';
// Get the data file
Future<File> get file async {
if (_file != null) return _file!;
_file = await _initFile();
return _file!;
}
// Initialize file
Future<File> _initFile() async {
final _directory = await getApplicationDocumentsDirectory();
final _path = _directory.path;
// Check if file exists
File file = File('$_path/$_fileName');
if(await file.exists() == false){
await file.create(recursive: true);
}
return file;
}
// Users
static Set<ShoppingListProduct> _shoppingListSet = {};
Future<void> writeShoppingList(ShoppingListProduct shoppingListProduct) async {
final File fl = await file;
_shoppingListSet.add(shoppingListProduct);
// Now convert the set to a list as the jsonEncoder cannot encode
// a set but a list.
final _shoppingListMap = _shoppingListSet.map((e) => e.toJson()).toList();
await fl.writeAsString(jsonEncode(_shoppingListMap));
}
Future<List<ShoppingListProduct>> readShoppingListProducts() async {
final File fl = await file;
final _content = await fl.readAsString();
List<dynamic> _jsonData = [];
if(_content.isNotEmpty){
_jsonData = jsonDecode(_content);
}
final List<ShoppingListProduct> _shoppingListProducts = _jsonData
.map(
(e) => ShoppingListProduct.fromJson(e as Map<String, dynamic>),
)
.toList();
return _shoppingListProducts;
}
Future<void> deleteShoppingListProduct(ShoppingListProduct shoppingListProduct) async {
final File fl = await file;
_shoppingListSet.removeWhere((e) => e == shoppingListProduct);
final _shoppingListMap = _shoppingListSet.map((e) => e.toJson()).toList();
await fl.writeAsString(jsonEncode(_shoppingListMap));
}
Future<void> updateShoppingListProduct({
required String key,
required ShoppingListProduct updatedShoppingListProduct,
}) async {
_shoppingListSet.removeWhere((e) => e.ID == updatedShoppingListProduct.ID);
await writeShoppingList(updatedShoppingListProduct);
}
Here's the product class.
class Product extends Equatable{
const Product({
required this.user,
required this.id,
required this.name,
required this.image,
required this.brandName,
required this.productPrices,
});
final String user;
final int id;
final String name;
final String image;
final String brandName;
final Map productPrices;
Product.fromJson(Map<String, dynamic> map)
: user = (map['user'] as String),
id = (map['id'] as int ).toInt(),
name = (map['name'] as String),
image = (map['image'] as String),
brandName = (map['brandName'] as String),
productPrices = (map['productPrices'] as Map<Retailers, double>);
Map<String, dynamic> toJson(){
return {
'user': user,
'id': id,
'name': name,
'image': image,
'brandName': brandName,
'productPrices': productPrices,
};
}
@override
String toString(){
return 'Product:\n\tId: $id\n\tName: $name\n\tImage: $image\n\tBrandName: $brandName\n\tProductPrices: $productPrices';
}
@override
List<Object> get props => [id, name, image, brandName, productPrices];
When I try and read the data I get the error seen in the title of this post. Any help would be highly appreciated. Thanks.
Here's the full stack trace
[VERBOSE-2:ui_dart_state.cc(198)] Unhandled Exception: Converting object to an encodable object failed: Instance of 'Product'
#0 _JsonStringifier.writeObject (dart:convert/json.dart:794:7)
#1 _JsonStringifier.writeMap (dart:convert/json.dart:875:7)
#2 _JsonStringifier.writeJsonValue (dart:convert/json.dart:830:21)
#3 _JsonStringifier.writeObject (dart:convert/json.dart:785:9)
#4 _JsonStringifier.writeList (dart:convert/json.dart:842:7)
#5 _JsonStringifier.writeJsonValue (dart:convert/json.dart:824:7)
#6 _JsonStringifier.writeObject (dart:convert/json.dart:785:9)
#7 _JsonStringStringifier.printOn (dart:convert/json.dart:983:17)
#8 _JsonStringStringifier.stringify (dart:convert/json.dart:968:5)
#9 JsonEncoder.convert (dart:convert/json.dart:345:30)
#10 JsonCodec.encode (dart:convert/json.dart:231:45)
#11 jsonEncode (dart:convert/json.dart:114:10)
#12 ShoppingListHandler.writeShoppingList (package:app/src/handlers/shopping_list_handler.dart:51:28)
Upvotes: 0
Views: 310
Reputation: 3668
Product
's productPrices
map, while untyped in the class declaration, can be seen to have a key of the Retailers
enum type in its fromJson
constructor.
Dart's JSON encoder does not automatically convert enums to strings. Consider adding a property to the enum for this purpose, or else use a package like json_serializable
.
Upvotes: 1