Home > Mobile >  JsonSerializable: How to toJson/fromJson correspond to subclass type?
JsonSerializable: How to toJson/fromJson correspond to subclass type?

Time:05-24

Let say I have data structure like this

@JsonSerializable(explicitToJson: true)
class CartItem {
  final Product product;
  ...
}

@JsonSerializable()
class Product {
  final String id;
  ...
}

@JsonSerializable()
class Food extends Product {
  final String foodName;
  ...
}

@JsonSerializable()
class Furniture extends Product {
  final String furnitureName;
  ...
}

What I want is when I use CartItem.toJson() it export to Json map correspond to what type of Product is.

For example

var x = CartItem(
          product: Food(
            id: '1100112',
            foodName: 'Hamburger',
          ),
        )
print(x.toJson());

this should result in

{
  'product': {
    'id': '1100112',
    'foodName': 'Hamburger',
  }
}

also when use fromJson, product will has type Food

x.fromJson(x.toJson()) as Food //This should not error

CodePudding user response:

I assume you're using the package json_serialization. For each class you would want to define some of the following methods:

For example:

factory CartItem.fromJson(Map<String, dynamic> json) => _$CartItemFromJson(json);
Map<String, dynamic> toJson() => _$CartItemToJson(this);

Then you would run the generating command line:

flutter pub run build_runner build

This will auto-generate a .g.dart file corresponding to your model file.

Reference: https://pub.dev/packages/json_serializable

Otherwise, if you wish to define the methods manually:

class CartItem {
  final Product product;
  CartItem({required this.product});
  /// fromJson
  factory CartItem.fromJson(Map<String, dynamic> json) => CartItem(
      product: Product.fromJson(json["product"])
  );
  /// toJson
  Map<String, dynamic> toJson() => {
    "product": product.toJson()
  };
}

class Product {
  final String id;
  Product({required this.id});
  /// fromJson
  factory Product.fromJson(Map<String, dynamic> json) => Product(
      id: json["id"]
  );

  /// toJson
  Map<String, dynamic> toJson() => {
    "id": id
  };
}

class Food extends Product {
  final String foodName;

  Food({required String id, required this.foodName}) : super(id: id);

  /// fromJson
  factory Food.fromJson(Map<String, dynamic> json) => Food(
      id: json["id"],
      foodName: json["foodName"]
  );

  /// toJson
  @override
  Map<String, dynamic> toJson() => {
    "id": id,
    "foodName": foodName
  };
}

class Furniture extends Product {
  final String furnitureName;

  Furniture({required String id, required this.furnitureName}) : super(id: id);

  /// fromJson
  factory Furniture.fromJson(Map<String, dynamic> json) => Furniture(
      id: json["id"],
      furnitureName: json["furnitureName"]
  );

  /// toJson
  @override
  Map<String, dynamic> toJson() => {
    "id": id,
    "furnitureName": furnitureName
  };
}

After defining, you can do:

var x = CartItem(
 product: Food(
  id: '1100112',
  foodName: 'Hamburger',
 ),
)
print(x.toJson());
  • Related