JsonSerializable:如何toJson/fromJson对应子类类型?

JsonSerializable: How to toJson/fromJson correspond to subclass type?

假设我有这样的数据结构

@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;
  ...
}

我想要的是当我使用 CartItem.toJson() 时它导出到 Json 映射对应于 Product 的类型。

例如

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

这应该导致

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

同样在使用 fromJson 时,产品的类型为 Food

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

我假设您正在使用包 json_serialization。对于每个 class,您需要定义以下一些方法:

例如:

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

然后你会运行生成命令行:

flutter pub run build_runner build

这将 auto-generate 一个 .g.dart 文件对应于您的 模型文件。

参考:https://pub.dev/packages/json_serializable

否则,如果您希望手动定义方法:

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

定义后,可以做:

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