1. Giới Thiệu
  • Package này hỗ trợ tạo các function để chuyển đổi từ model của dart sang chuỗi json và ngược lại.

  • Các annotation sẽ giúp tool nhận biết phần nào sẽ được generate code.

  • Các bước cài đặt gói này, vui lòng tham khảo document.

    • json_annotation

    • json_serializable

    • build_runner

2. Chuẩn bị model
  • Khai báo một model cần dùng cho App

  • Khai báo các field cần thiết.

  • Khai báo function là toJson(), để chuyển model sang chuỗi json.

  • Khai báo function fromJson(), để chuyển chuỗi json về model

  • Ví dụ : Chúng ta có model Student như sau :

    class Student {
      String name;
      int age;
      String address;
      Student({
        required this.name,
        required this.age,
        required this.address,
      });
      
      factory Student.fromJson(Map<String, dynamic> json) =>
          _$StudentFromJson(json);
      Map<String, dynamic> toJson() => _$StudentToJson(this);
    }
      
    
    • _$StudentFromJson : Function này sẽ được tạo tự động

    • _$StudentToJson : Function này sẽ đươc tạo tự động

2. JsonSerializable
  • Chúng ta đã chuẩn bị được model, giờ làm sao để nó generate ra code cho mình ??. Gắn @JsonSerializable vào trên đầu của class Student.

    @JsonSerializable()
    class Student {
      String name;
      int age;
      String address;
      Student({
        required this.name,
        required this.age,
        required this.address,
      });
      
      factory Student.fromJson(Map<String, dynamic> json) =>
          _$StudentFromJson(json);
      Map<String, dynamic> toJson() => _$StudentToJson(this);
    }
    
  • Sau đó thực hiện lệnh build này : dart run build_runner build

  • Code sau khi được tạo :

    Student _$StudentFromJson(Map<String, dynamic> json) => Student(
          name: json['name'] as String,
          age: json['age'] as int,
          address: json['address'] as String,
        );
      
    Map<String, dynamic> _$StudentToJson(Student instance) => <String, dynamic>{
          'name': instance.name,
          'age': instance.age,
          'address': instance.address,
        };
    
  • Một số tham số của @JsonSerializable

    • anyMap

      • Nếu true, các type [Map] không được hiểu rằng [Map<String, dynamic>]. Nó là type mặc định của các instance [Map] trả về bởi JSON decode trong dart:convert

      • Điều này làm tăng size code nhưng nó cho phép trả về từ nhiều nguồn khác nhau.

    • checked :

      • Nếu true, function fromJson sẽ có thêm function checkedCreate để kiểm tra tính hợp lệ của quá trình deserialization. Nếu không hợp lệ thì sẽ có exception ném ra.

        Student _$StudentFromJson(Map<String, dynamic> json) => $checkedCreate(
        
    • constructor :

      • Chỉ định rằng named contrunctor sẽ được dùng để tạo đối tượng từ function fromJson. Nếu khống set thì contrunctor mặc định sẽ được dùng.

        @JsonSerializable(
          checked: true,
          constructor: "elementary",
        )
        class Student {
          String name;
          int age;
          String address;
              
          // Named Contructor
          Student.elementary({
            required this.name,
            required this.age,
            required this.address,
          });
        }
        
        Student _$StudentFromJson(Map<String, dynamic> json) => $checkedCreate(
              'Student',
              json,
              ($checkedConvert) {
                // Dùng named contructor.
                final val = Student.elementary(
                  name: $checkedConvert('name', (v) => v as String),
                  age: $checkedConvert('age', (v) => v as int),
                  address: $checkedConvert('address', (v) => v as String),
                );
                return val;
              },
            );
        
    • createFactory :

      • Mặc định là true, nếu set false function FromJson sẽ không được tạo.

        Student _$StudentFromJson(Map<String, dynamic> json) => $checkedCreate(
        
    • createFieldMap :

      • Nếu là true (mặc định là false), một private, static _$ExampleJsonMeta constants sẽ được tạo. Contants này sẽ được dùng bởi code-generators khác để hỗ trợ các tính năng.

        const _$StudentFieldMap = <String, String>{
          'name': 'name',
          'age': 'age',
          'address': 'address',
        };
        
    • createPerFieldToJson :

      • Mặc định là false, nếu là true, một private, static _$ExamplePerFieldToJson abstract class sẽ được tạo. class này chứa một per property trình bày cách để encode chỉ một property thay vì nguyên đối tượng

        // ignore: unused_element
        abstract class _$StudentPerFieldToJson {
          // ignore: unused_element
          static Object? name(String instance) => instance;
          // ignore: unused_element
          static Object? age(int instance) => instance;
          // ignore: unused_element
          static Object? address(String instance) => instance;
        }
        
    • createToJson :

      • Mặc định là true, môt function cấp cấp nhất được tạo cái mà bạn có thể tham chiếu đến class của mình. Dùng để chuyển đổi model sang chuỗi json.

        Map<String, dynamic> _$StudentToJson(Student instance) => <String, dynamic>{
              'name': instance.name,
              'age': instance.age,
              'address': instance.address,
            };
        
    • disallowUnrecognizedKeys :

      • Mặc định là false, function FromJson sẽ bỏ qua các key không nhận trong JSON [Map]. Nếu true, các key không nhận sẽ bị ném exception
    • explicitToJson :

      • Nếu là true, method toJson sẽ gọi ngầm định gọi toJson của nest objects. Khi dùng JSON encoding trong dart:converter, toJson tự động được gọi, vì vậy nó là hành vi mặc định (explicitToJson: false)

        // Example of `explicitToJson: false` (default)
        Map<String, dynamic> toJson() => {'child': child};
              
        // Example of `explicitToJson: true`
        // Map<String, dynamic> toJson() => {'child': child?.toJson()};
        
    • fieldRename :

      • Mặc định là [FieldRename.none] name của field không có chỉnh sửa

      • [FieldRename.kebab]

        Map<String, dynamic> _$StudentToJson(Student instance) => <String, dynamic>{
              'name': instance.name,
              'age': instance.age,
              'address-student': instance.addressStudent,
            };
        
      • [FieldRename.pascal]

        Map<String, dynamic> _$StudentToJson(Student instance) => <String, dynamic>{
              'Name': instance.name,
              'Age': instance.age,
              'AddressStudent': instance.addressStudent,
            };
        
      • [FieldRename.screamingSnake]

        Map<String, dynamic> _$StudentToJson(Student instance) => <String, dynamic>{
              'NAME': instance.name,
              'AGE': instance.age,
              'ADDRESS_STUDENT': instance.addressStudent,
            };
        
      • [FieldRename.screamingSnake]

        Map<String, dynamic> _$StudentToJson(Student instance) => <String, dynamic>{
              'name': instance.name,
              'age': instance.age,
              'address_student': instance.addressStudent,
            };
        
    • genericArgumentFactories

      • Khi set true, nó sẽ hỗ trợ generate các method generic.

          @JsonSerializable(genericArgumentFactories: true)
          class Response<T> {
             int status;
             T value;
           }
        
           Response<T> _$ResponseFromJson<T>(
             Map<String, dynamic> json,
             T Function(Object json) fromJsonT,
           ) {
             return Response<T>()
               ..status = json['status'] as int
               ..value = 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),
               };
        
      • Tuỳ chọn này không có tác động gì trên class không có generic.

      • Nếu tuỳ chọn này được set tất cả các class thông qua build.yaml thì nó chỉ apply với các class có generic

    • ignoreUnannotated :

      • Khi set true, chỉ các field được annotate với JsonKey nới được generated.
    • converters :

      • Hỗ trợ chuyển đổi giá trị theo logic cụ thể.

        class DateTimestampConverter implements JsonConverter<DateTime?, Timestamp?> {
          const DateTimestampConverter();
              
          @override
          DateTime? fromJson(Timestamp? timestamp) => timestamp?.toDate();
              
          @override
          Timestamp? toJson(DateTime? dateTime) => dateTime != null ? Timestamp.fromDate(dateTime) : null;
        }
        
        @JsonSerializable(
          explicitToJson: true,
          converters: [DateTimestampConverter()],
        )
        
    3. JsonKey
    • Với @JsonSerializable được gắn trên class, thì @JsonKey sẽ được gắn trên các filed của model.

    • Một số thuộc tính :

      • defaultValue : Giá trị mặc định của field.

      • disallowNullValue : Không cho phép field này bị null.

      • includeFromJson : Bỏ qua filed này khi toJson hoặc fromJson