A.K.
A.K.

Reputation: 683

clean architecture toJson with sublist (reso coder)

I am trying to use clean architecture (explained by reso coder: https://resocoder.com/2019/09/09/flutter-tdd-clean-architecture-course-4-data-layer-overview-models/) in my project.

In his example, he implements an entity and a model extending the entity. The entity has all of the properties and the model implements the fromJson and toJson Methods.

It works well with "flat" classes.

But now I want to implement that for a class that has a list of other classes.

class Item {
    String text;
}

class ItemModel extends Item{
  ...toJson
  ...romJson
}

class Order {
  ...
  List<Item> items;
}

class OrderModel extends Item {
  ...

  ...fromJson() {
     if (json['items'] != null) {
            teams = new List<ItemModel>();
            json['items'].forEach((v) {
                items.add(Item.fromJson(v));
            });
     }
  }
}

...toJson(){
    final Map<String, dynamic> data = new Map<String, dynamic>();
    if (this.items!= null) {
        data['items'] = this.items.map((v) => v.toJson()).toList();
    }
    return data;
}

Of course it doesn´t work, because the class item does not have a method "toJson".

What is the correct way to implement it? Cast the List to List in the toJson method.

EDIT

When I try to cast the list items to ItemModel and there is an Item in the list, then an exception is thrown:

  type 'Item' is not a subtype of type 'ItemModel' in type cast

I would now consider the following to be correct: Add a factory method to the ItemModel that cast an Item to an ItemModel:

fromItem(Item item){ 
     if(item is ItemModel) {
       return item as ItemModel;
     }
     return ItemModel(..: item...);
  }

Is that the best way to solve this?

Upvotes: 4

Views: 1063

Answers (2)

A.K.
A.K.

Reputation: 683

I now solved it in the following way.

I´ve added a method to the model class to cast the entity to the model

factory ItemModel.fromItem(Item item) {
    if (item is ItemModel) {
      return item;
    }
    return ItemModel(
      text: item.text,
    );
  }

And adapted the toJson method

...toJson(){
      final Map<String, dynamic> data = new Map<String, dynamic>();
      if (this.items != null) {
      data['items'] = this.items.map((v) => ItemModel.fromItem(v).toJson()).toList();
      }
      return data;
}

Upvotes: 2

dm_tr
dm_tr

Reputation: 4763

You are using Item.fromJson instead of ItemModel.fromJson ? Have you tried this ?

class OrderModel extends Item {
  ...

  ...fromJson() {
     if (json['items'] != null) {
        teams = new List<ItemModel>();
        json['items'].forEach((v) {
            items.add(ItemModel.fromJson(v));
        });
     }
  }
}

Edit
If you to call toJson on Item directly, you can cast it's value to ItemModel as following

...toJson(){
      final Map<String, dynamic> data = new Map<String, dynamic>();
      if (this.items != null) {
          data['items'] = this.items.map((v) => (v as ItemModel).toJson()).toList();
      }
      return data;
}

Edit 2
Make your Item class abstract and add abstract methods fromJson a and toJson

abstract class Item {
   //...
  
   Item fromJson(Map json); // abstract method
   Map<String, dynamic> toJson(); // abstract method
   
}

Upvotes: 1

Related Questions