[Flutter]Json序列化json_serializable使用属性全介绍

结合上一篇介绍[Flutter]Json和序列化数据,看浏览关注的人还是很多。这里出一篇详细介绍json_serializable的属性参数的解析说明。此文章根据目前最新版本json_serializable: ^6.9.0介绍 ,下面开始:

一、一般使用介绍

Dart 复制代码
// json_serializable模型写法示意
import 'package:json_annotation/json_annotation.dart';
//当前文件名+.g.dart
part 'device_model.g.dart';

//添加注解
@JsonSerializable()
class DeviceTypeNetModel {
  final num? deviceType;
  final String? deviceTypeName;
  //自定义一些属性的某些设置
  @JsonKey(name: 'num')
  final int? count;

//构造函数
  DeviceTypeNetModel(this.deviceType, this.deviceTypeName, this.count);

//工厂构造函数fromJson(也可以不写,需要配置对应的设置)
  factory DeviceTypeNetModel.fromJson(Map<String, dynamic> json) =>
      _$DeviceTypeNetModelFromJson(json);

//转json (也可以不写,需要配置对应的设置)
  Map<String, dynamic> toJson() => _$DeviceTypeNetModelToJson(this);
}

二、JsonKey参数解析

defaultValue:Object?

  • 功能:指定字段的默认值。当 JSON 中没有该字段时,将使用 defaultValue 提供的值。
  • 用法:如果 JSON 数据中某个字段缺失,defaultValue 可以为其提供默认值,避免字段变为 null 或触发错误。
Dart 复制代码
@JsonKey(defaultValue: 'Unknown')
final String name;

如果 JSON 数据中没有 name 字段,默认值 Unknown 会被使用。

disallowNullValue:bool?

  • 功能:用于toJson的时候防止字段值为 null,如果字段的值为 null,会抛出 ArgumentError。
  • 用法:用于要求某个字段永远不能为 null,如果传入 null,则会抛出异常。
Dart 复制代码
@JsonKey(disallowNullValue: true)
final String name;

如果 name 字段为 null,在序列化时将抛出错误。

fromJson 和 toJson : Function?

  • 功能:用于指定自定义的序列化和反序列化函数。这对于复杂的数据类型或者需要特殊处理的字段特别有用。
  • 用法:可以通过 fromJson 来指定如何将 JSON 数据转换为 Dart 对象,toJson 用于指定如何将 Dart 对象转换为 JSON。
Dart 复制代码
@JsonKey(fromJson: _fromJson, toJson: _toJson)
final DateTime timestamp;

static DateTime _fromJson(String timestamp) {
  return DateTime.parse(timestamp);
}

static String _toJson(DateTime timestamp) {
  return timestamp.toIso8601String();
}

这里,timestamp 字段会使用自定义的 fromJson 和 toJson 方法进行解析和序列化。

name: String?

  • 功能:用于指定字段在 JSON 中的键名。通常在 Dart 类字段名与 JSON 中的键名不匹配时使用。
  • 用法:如果 Dart 类中的字段名与 JSON 中的字段名不一致,可以使用 name 指定要使用的 JSON 键。
Dart 复制代码
@JsonKey(name: 'full_name')
final String name;

在上面的示例中,name 字段会被序列化为 full_name,而不是默认的 name。

includeFromJson 和 includeToJson : bool?

  • 功能:如果设置为 true,该字段将被忽略,在 toJson 和 fromJson 中都不会参与序列化和反序列化。不会影响模型基准构造函数的赋值使用。
  • 用法:用于那些不希望在 JSON 中进行序列化和反序列化的字段。
Dart 复制代码
@JsonKey(includeFromJson: true,includeToJson: true)
final String temporaryData;

这里,temporaryData 字段将不会出现在生成的 JSON 中,并且也不会参与 fromJson 过程。

includeIfNull:bool?

  • 功能:用于控制字段是否在 toJson 时包含 null 值。如果设置为 false,该字段即使为 null 也会被忽略。(默认从默认配置中获取即为true)
  • 用法:常用于希望在序列化时避免生成冗余的 null 字段。
Dart 复制代码
@JsonKey(includeIfNull: false)
final String? email;

如果 email 字段为 null,它将不会出现在生成的 JSON 中。

readValue: Object? Function(Map,Srting)?

  • 功能:用于转化接口返回的类型。(有局限性,建议使用fromJson和toJson替换)
  • 用法:常用于希望在接收使用的数据类型和接口返回的json中字段类型不一致的情况。
Dart 复制代码
@JsonKey(readValue: NormalTool.transFromMill)
final String timeMill;

class NormalTool {
  static String transFromMill(Map p0, String p1) {
    return p0[p1].toString();
  }
}

//注意这里转化基本类型可以,但是如果是DateTime类型会出现不属于基本类型的转化toJson会被定义为String,进而影响fromJson的转化。

例如上述的如果转化为DateTime,得到的.g.dart的转化内容如下:

Dart 复制代码
DeviceTypeNetModel _$DeviceTypeNetModelFromJson(Map<String, dynamic> json) =>
    DeviceTypeNetModel(
      DateTime.parse(NormalTool.transFromMill(json, 'timeMill') as String),
    );

Map<String, dynamic> _$DeviceTypeNetModelToJson(DeviceTypeNetModel instance) =>
    <String, dynamic>{
      'timeMill': instance.timeMill.toIso8601String(),
    };

required:bool?

  • 功能:表示该字段在 JSON 中是必须的,必须提供该字段的值。和构造函数标注属性必须有内容类似。
  • 用法:当你需要确保某个字段在序列化时不为 null 并且 JSON 中必须包含该字段时,可以使用此属性。
Dart 复制代码
@JsonKey(required: true)
final String name;

这意味着,name 字段在 JSON 中是必须存在的,否则解析时会抛出异常。

unknownEnumValue : Enum?

  • 功能:用于处理枚举类型的字段。当 JSON 数据包含一个未在 Dart 枚举中定义的值时,使用 unknownEnumValue 来指定默认值。
  • 用法:非常有用,尤其是在处理与外部 API 交互时,API 可能会传回新的、未在枚举中定义的值。
Dart 复制代码
@JsonKey(unknownEnumValue: Gender.other)
final Gender gender;

如果 JSON 中的 gender 字段值不是枚举中定义的 male、female,则默认使用 Gender.other。

三、JsonSerializable参数解析

anyMap:bool?

  • 类型:bool,默认值是 false。
  • 描述:如果为 true,则会将 Map 的 fromJson 方法生成的参数类型从 Map 改为 Map。这可以用于处理一些动态类型的数据。
Dart 复制代码
@JsonSerializable(anyMap: true)
class User {
  final String name;

  User({required this.name});
}

checked: bool?

  • 类型:bool,默认值是 false。
  • 描述:如果为 true,则会将fromJson按照类型校验类型正确的反序列化,如果类型校验不通过则会抛出异常CheckedFromJsonException
Dart 复制代码
@JsonSerializable(checked: true)
class User {
  final String name;

  User({required this.name});
}

constructor: String?

  • 类型:String?,默认值是 null。
  • 描述:指定一个构造函数的名称。如果你的类有多个构造函数,或者需要通过特定的构造函数来创建对象,可以使用此参数。
Dart 复制代码
@JsonSerializable(constructor: 'customConstructor')
class User {
  final String name;

  User.customConstructor({required this.name});
}

在这个例子中,User 类会使用 customConstructor 来生成实例。

createFieldMap: bool?

  • 类型:bool,默认值是 false。
  • 描述:如果为 true,则会创建一个私有的方法_$ExampleJsonMeta 返回模型名称对应Json的key
Dart 复制代码
@JsonSerializable(createFieldMap: true)
class DeviceTypeNetModel {
  final num? deviceType;
  final String? deviceTypeName;
  @JsonKey(name: 'num')
  final int? count;
  final DeviceListCountNetModel model;
  
  DeviceTypeNetModel(this.deviceType, this.deviceTypeName, this.count, this.model);
  
  Map<String, String> fieldMap() => _$DeviceTypeNetModelFieldMap;
}

.g.dart 会多一个内部私有方法
const _$DeviceTypeNetModelFieldMap = <String, String>{
  'deviceType': 'deviceType',
  'deviceTypeName': 'deviceTypeName',
  'count': 'num',
  'model': 'model',
};

createJsonKeys: bool?

  • 类型:bool,默认值是 false。
  • 描述:同上createFieldMap,内部创建一个私有的_$ExampleJsonKeys,创建一个静态的字符常量定义,变量名为项目属性名,指向内容是Json的key。
Dart 复制代码
@JsonSerializable(createJsonKeys: true)
class DeviceTypeNetModel {
  final num? deviceType;
  final String? deviceTypeName;
  @JsonKey(name: 'num')
  final int? count;
  final DeviceListCountNetModel model;
  
  DeviceTypeNetModel(this.deviceType, this.deviceTypeName, this.count, this.model);
}

.g.dart 会多一个内部私有方法
abstract final class _$DeviceTypeNetModelJsonKeys {
  static const String deviceType = 'deviceType';
  static const String deviceTypeName = 'deviceTypeName';
  static const String count = 'num';
  static const String model = 'model';
}

createFactory: bool?

  • 类型:bool,默认值是 true。
  • 描述:如果为 false,不会为该类生成 fromJson 工厂方法。可以通过手动定义 fromJson 工厂方法来控制反序列化过程。
Dart 复制代码
@JsonSerializable(createFactory: false)
class User {
  final String name;

  User({required this.name});

  // 手动定义 fromJson 方法
  static User fromJson(Map<String, dynamic> json) {
    return User(name: json['name']);
  }
}

createToJson: bool?

  • 类型:bool,默认值是 true。
  • 描述:如果为 false,则不生成 toJson 方法。你可以手动定义自己的 toJson 方法,或者完全不需要序列化成 JSON。
Dart 复制代码
@JsonSerializable(createToJson: false)
class User {
  final String name;

  User({required this.name});

  // 手动定义 toJson 方法
  Map<String, dynamic> toJson() {
    return {'name': name};
  }

disallowUnrecognizedKeys: bool?

  • 类型:bool,默认值是 false。
  • 描述:默认false,表示fromJson中的JSON有多余的字段忽略,如果设置为true,则JSON存在多余的key会抛出异常}UnrecognizedKeysException

explicitToJson: bool?

  • 类型:bool,默认值是 false。
  • 描述:如果为 true,则嵌套对象的 toJson 方法会被显式调用。默认情况下,json_serializable 会递归地将对象转化为 JSON,而不需要显式调用嵌套类的 toJson 方法。如果你希望强制嵌套对象也使用自己的 toJson,可以设置为 true。
Dart 复制代码
@JsonSerializable(explicitToJson: true)
class User {
  final String name;
  final Address address;

  User({required this.name, required this.address});

  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
  Map<String, dynamic> toJson() => _$UserToJson(this);
}

@JsonSerializable()
class Address {
  final String city;
  final String street;

  Address({required this.city, required this.street});

  factory Address.fromJson(Map<String, dynamic> json) => _$AddressFromJson(json);
  Map<String, dynamic> toJson() => _$AddressToJson(this);
}

在这个例子中,User 类会显式调用 Address 类的 toJson,而不依赖于 json_serializable 的递归自动处理。

fieldRename: FieldRename?

  • 类型:FieldRename,可以设置为 none(默认值),snake , kebab,pascal,screamingSnake。
  • 描述:指定字段名的转换规则,通常用于处理 Dart 中的驼峰命名和 JSON 中的下划线命名。
    • none:保留原字段名(默认值)。
    • snake:将字段名转换为蛇形命名(camelCase -> snake_case)。
    • kebab:将字段名转换为短横线命名(camelCase -> kebab-case)。
    • pascal: 将字段名转换为大驼峰命名(pascalCase -> PascalCase)。
    • screamingSnake: 将字段名转换为单词大写下划线连接 (screamingSnakeCase -> SCREAMING_SNAKE_CASE)。
Dart 复制代码
@JsonSerializable(fieldRename: FieldRename.snake)
class User {
  final String firstName;
  final String lastName;

  User({required this.firstName, required this.lastName});
}

在这个例子中,firstName 会被转换为 first_name,lastName 会被转换为 last_name。

ignoreUnannotated: bool?

  • 类型:bool,默认值是 false。
  • 描述:如果为 true,则 json_serializable 会忽略没有被 @JsonKey 标注的字段。这对于类中有很多字段,但只希望某些字段进行序列化时非常有用。
Dart 复制代码
@JsonSerializable(ignoreUnannotated: true)
class User {
  final String name;
  @JsonKey(name: 'age_in_years')
  final int age;

  User({required this.name, required this.age});
}

如果你设置了 ignoreUnannotated: true,name 字段不会被包含在生成的 toJson 和 fromJson 方法中,只有 age 字段会被序列化。

includeIfNull: bool?

  • 类型:bool,默认值是 true。
  • 描述:针对toJson,如果值是null的时候是否写入导出的JSON中。

converters: List?

  • 类型:List
  • 描述:自定义解释器,内部的fromJson和toJson都将自定义实现,取消自动生成的转化。
Dart 复制代码
@JsonSerializable(converters: [MyJsonConverter()])
class Example {
 //也可以单独指定某一个属性做特殊自定义解释
 //@MyJsonConverter()
  final DateTime property;

  Example(this.property);
}

class MyJsonConverter extends JsonConverter<DateTime, String> {
  const MyJsonConverter();

  @override
  DateTime fromJson(String json) {
    return DateTime.parse(json);
  }

  @override
  String toJson(DateTime object) {
    return '';
  }
}

genericArgumentFactories: bool?

  • 类型:bool,默认值是 false。
  • 描述:针对范型,下面第四块会做介绍使用。

createPerFieldToJson: bool?

  • 类型:bool,默认值是 false。
  • 描述:会创建一个私有方法 _$ExamplePerFieldToJson 。这个抽象类将为每个属性包含一个静态函数,从而提供了一种仅对该属性而不是整个对象进行设置的方法。
Dart 复制代码
@JsonSerializable(createPerFieldToJson: true)
class DeviceTypeNetModel {
  final num? deviceType;
  final String? deviceTypeName;
  @JsonKey(name: 'num')
  final int? count;
  final DeviceListCountNetModel model;
  
  DeviceTypeNetModel(this.deviceType, this.deviceTypeName, this.count, this.model);
}

.g.dart 会多一个内部私有方法

// ignore: unused_element
abstract class _$DeviceTypeNetModelPerFieldToJson {
  // ignore: unused_element
  static Object? deviceType(num? instance) => instance;
  // ignore: unused_element
  static Object? deviceTypeName(String? instance) => instance;
  // ignore: unused_element
  static Object? count(int? instance) => instance;
  // ignore: unused_element
  static Object? model(DeviceListCountNetModel instance) => instance;
}

四、范型T

json serializable 在大概两年前发布的v3.5.0版本开始支持泛型,只需要在 @JsonSerializable() 注解中设置genericArgumentFactories为 true,同时需要对 fromJson 和 toJson 方法进行调整,即可支持泛型解析,如下所示:

Dart 复制代码
@JsonSerializable(genericArgumentFactories: true) 
class Response<T> { 
int status; 
T value; 

factory Response.fromJson(Map<String, dynamic>json, T Function(dynamic json) fromJsonT) => _$ResponseFromJson<T>(json, fromJsonT);

Map<String, dynamic> toJson(Object? Function(T value) toJsonT) => _$ResponseToJson<T>(this, toJsonT);
}


得到的.g.dart 文件内容如下:
Response<T> _$ResponseFromJson<T>(
  Map<String, dynamic> json,
  T Function(Object? json) fromJsonT,
) =>
    Response<T>(
      (json['status'] as num).toInt(),
      fromJsonT(json['value']),
    );

Map<String, dynamic> _$ResponseToJson<T>(
  Response<T> instance,
  Object? Function(T value) toJsonT,
) =>
    <String, dynamic>{
      'status': instance.status,
      'value': toJsonT(instance.value),
    };

适用于一些固定结构,可以预处理一部分业务,其中某个参数根据业务变化在外部处理业务的场景(接口响应很经典)。

五、枚举

Dart 复制代码
enum StatusCode {
  @JsonValue(200)
  success,
  @JsonValue(301)
  movedPermanently,
  @JsonValue(302)
  found,
  @JsonValue(500)
  internalServerError,
}
@JsonSerializable()
class BackModel {
  StatusCode code;

  BackModel(this.code);
  factory BackModel.fromJson(Map<String, dynamic> json) =>
      _$BackModelFromJson(json);

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

得到的.g.dart 文件内容如下:

BackModel _$BackModelFromJson(Map<String, dynamic> json) => BackModel(
      $enumDecode(_$StatusCodeEnumMap, json['code'])
    );

Map<String, dynamic> _$BackModelToJson(BackModel instance) => <String, dynamic>{
      'code': _$StatusCodeEnumMap[instance.code]!,
    };

const _$StatusCodeEnumMap = {
  StatusCode.success: 200,
  StatusCode.movedPermanently: 301,
  StatusCode.found: 302,
  StatusCode.internalServerError: 500,
};

或者

Dart 复制代码
@JsonEnum(valueField: 'code')
enum StatusCodeEnhanced {
  success(200),
  movedPermanently(301),
  found(302),
  internalServerError(500);

  const StatusCodeEnhanced(this.code);
  final int code;
}
@JsonSerializable()
class BackModel {
  StatusCodeEnhanced status;

  BackModel(this.status);

  factory BackModel.fromJson(Map<String, dynamic> json) =>
      _$BackModelFromJson(json);

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


得到的.g.dart 文件内容如下:

BackModel _$BackModelFromJson(Map<String, dynamic> json) => BackModel(
      $enumDecode(_$StatusCodeEnhancedEnumMap, json['status']),
    );

Map<String, dynamic> _$BackModelToJson(BackModel instance) => <String, dynamic>{
      'status': _$StatusCodeEnhancedEnumMap[instance.status]!,
    };

const _$StatusCodeEnhancedEnumMap = {
  StatusCodeEnhanced.success: 200,
  StatusCodeEnhanced.movedPermanently: 301,
  StatusCodeEnhanced.found: 302,
  StatusCodeEnhanced.internalServerError: 500,
};

枚举记得使用注解unknownEnumValue,以便后续代码健壮性 @JsonKey(unknownEnumValue: Gender.other)

相关推荐
_风中无我。20 小时前
Spring的过滤器获取请求体中JSON参数,同时解决Controller获取不到请求体参数的问题。
java·spring·json
whisperrr.1 天前
【JavaWeb12】数据交换与异步请求:JSON与Ajax的绝妙搭配是否塑造了Web的交互革命?
前端·ajax·json
江上清风山间明月1 天前
Flutter开发的应用页面非常多时如何高效管理路由
android·flutter·路由·页面管理·routes·ongenerateroute
子非衣1 天前
MySQL修改JSON格式数据示例
android·mysql·json
Zsnoin能1 天前
flutter国际化、主题配置、视频播放器UI、扫码功能、水波纹问题
flutter
早起的年轻人1 天前
Flutter CupertinoNavigationBar iOS 风格导航栏的组件
flutter·ios
HappyAcmen1 天前
关于Flutter前端面试题及其答案解析
前端·flutter
coooliang2 天前
Flutter 中的单例模式
javascript·flutter·单例模式
coooliang2 天前
Flutter项目中设置安卓启动页
android·flutter
JIngles1232 天前
flutter将utf-8编码的字节序列转换为中英文字符串
java·javascript·flutter