JsonSerializable与dart中的子类

g9icjywg  于 9个月前  发布在  其他
关注(0)|答案(3)|浏览(88)

我有一个对象层次结构,我想使用dart类将其序列化为json。下面是一个sudo代码示例:

@JsonSerializable(nullable: true)
class Person {
  int age;
}

@JsonSerializable(nullable: true)
class Athlete extends Person {
  int speed;
}

@JsonSerializable(nullable: true)
class BaseballPlayer extends Athlete {
  int height;
}

@JsonSerializable(nullable: true)
class Building {
  List<Person> people = []; 

  Building(){
    people.add(Person());
    people.add(Athlete());
    people.add(BaseballPlayer());
  }
}

字符串
我可以把这个流出来,但是当我读回来的时候,people里面有三个“Person“.. NOT a Person,Athlete和BaseballPlayer。它不知道如何加载特定的子类类型。我该如何处理这个?

wooyq4lh

wooyq4lh1#

您可以使用Morphy https://pub.dev/packages/morphy来实现这一点。
(我是软件包的开发者)
它可以将json序列化和重新序列化为子类型。

test("1", () {
  var building = Building(people: [
    Person(age: 1),
    Athlete(age: 2, speed: 3),
    BaseballPlayer(age: 4, speed: 5, height: 6),
  ]);

  var json = building.toJson_2();
  var building2 = Building.fromJson(json);

  expect(building2, building);
});

@Morphy(generateJson: true, explicitSubTypes: [$Athlete, $BaseballPlayer])
abstract class $Person {
  int get age;
}

@Morphy(generateJson: true, explicitSubTypes: [$BaseballPlayer])
abstract class $Athlete implements $Person {
  int get speed;
}

@Morphy(generateJson: true)
abstract class $BaseballPlayer implements $Athlete {
  int get height;
}

@Morphy(generateJson: true)
abstract class $Building {
  List<$Person> get people;
}

字符串

pwuypxnk

pwuypxnk2#

您可以添加相应的枚举类型作为runtimeType指针

enum PlantType {plant, tomato, potato};

@JsonSerializable(
  explicitToJson: true,
)
class Plant {

  final PlantType classType;
  final String name;

  Plant({required this.name, required this.classType});

  factory Plant.fromJson(Map<String, dynamic> json) {
    switch ($enumDecodeNullable(_$PlantTypeEnumMap, json['classType'])) {
      case PlantType.potato:
        return Potato.fromJson(json);
      case PlantType.tomato:
        return Tomato.fromJson(json);
      case PlantType.plant:
        return Plant.fromJson(json);
      default:
        throw 'Unimplemented type of Plant: ${json['classType']}';
    }
  }

  Map<String, dynamic> toJson() => _$PlantToJson(this);
}

@JsonSerializable(
  explicitToJson: true,
)
class Potato extends Plant {

  final bool couldBeFried;

  Potato({required this.couldBeFried, required String name})
    : super(name: name, classType: PlantType.potato);

  /// check out if _$PotatoFromJson does super's fromJson()
  factory Potato.fromJson(Map<String, dynamic> json) => _$PotatoFromJson(json);

  @override
  Map<String, dynamic> toJson() => {
    /** check out if _$PotatoToJson does super.toJson(), or apply it as ...super.toJson() */
    ..._$PotatoToJson(this),
  };
}

@JsonSerializable(
  explicitToJson: true,
)
class Tomato extends Plant {

  final bool isApplicableToSalad;

  Tomato({required this.isApplicableToSalad, required String name})
    : super(name: name, classType: PlantType.tomato);

  /// check out if _$TomatoFromJson does super's fromJson()
  factory Tomato.fromJson(Map<String, dynamic> json) => _$TomatoFromJson(json);

  @override
  Map<String, dynamic> toJson() => {
    /** check out if _$TomatoToJson does super.toJson(), or apply it as ...super.toJson() */
    ..._$TomatoToJson(this),
  };
}

字符串

hmae6n7t

hmae6n7t3#

结晶化:
1.你应该为基类定义特殊的工厂方法来实现子类。
1.此外,它可以包含自己的运行时类型字符串的属性。
1.对应于子类,你应该在基类的工厂方法fromJson中使用它们的fromJson方法。
序列化:
1.你应该在子类中覆盖toJson。

  1. toJson应该将MapEntry添加到json map(直接)。Map Entry应该包含运行时类型字符串。
    举个例子,代码如下:
const runtimeTypeSerialName = 'runtimeType';

@JsonSerializable(
  explicitToJson: true,
)
class Plant {

  final String name;

  Plant({this.name});

  factory Plant.fromJson(Map<String, dynamic> json) {
    final runType = json[runtimeTypeSerialName]! as String;
    switch (stringToRuntimeType(runType)) {
      case Potato:
        return Potato.fromJson(json);
      case Tomato:
        return Tomato.fromJson(json);
      default:
        throw 'Unimplemented type of Plant: $runType';
    }
  }

  Map<String, dynamic> toJson() => _$PlantToJson(this);

  
  /// could be replaced with property of type "enum PlantType {plant, potato, tomato};"
  static String runtimeTypeToString<T extends Plant>() {
    switch(T) {
      case Potato:
        return 'Potato';
      case Tomato:
        return 'Tomato';
      default:
        throw 'Unimplemented type of Plant';
    }
  }

  /// could be replaced with property of type "enum PlantType {plant, potato, tomato};"
  static Type stringToRuntimeType(String runtimeType) {
    switch(runtimeType) {
      case 'Potato':
        return Potato;
      case 'Tomato':
        return Tomato;
      default:
        throw 'Unimplemented type of Plant: $runtimeType';
    }
  }
}

@JsonSerializable(
  explicitToJson: true,
)
class Potato extends Plant {

  final bool couldBeFried;

  Potato({required this.couldBeFried, required super.name});

  /// check out if _$PotatoFromJson does super's fromJson()
  factory Potato.fromJson(Map<String, dynamic> json) => _$PotatoFromJson(json);

  @override
  Map<String, dynamic> toJson() => {
    /** check out if _$PotatoToJson does super.toJson(), or apply it as ...super.toJson() */
    ..._$PotatoToJson(this),
    ...{runtimeTypeSerialName: Plant.runtimeTypeToString<Potato>()},
  };
}

@JsonSerializable(
  explicitToJson: true,
)
class Tomato extends Plant {

  final bool isApplicableToSalad;

  Tomato({required this.isApplicableToSalad, required super.name});

  /// check out if _$TomatoFromJson does super's fromJson()
  factory Tomato.fromJson(Map<String, dynamic> json) => _$TomatoFromJson(json);

  @override
  Map<String, dynamic> toJson() => {
    /** check out if _$TomatoToJson does super.toJson(), or apply it as ...super.toJson() */
    ..._$TomatoToJson(this),
    ...{runtimeTypeSerialName: Plant.runtimeTypeToString<Tomato>()},
  };
}

字符串

相关问题