openplanning

Dart JSON với thư viện dart:convert

  1. dart:convert
  2. jsonDecode(..)
  3. jsonEncode(..)

1. dart:convert

Trong nhiều ứng dụng Dart/Flutter, bạn khá thường xuyên phải làm việc với các dữ liệu có định dạng JSON. Trong bài viết này chúng ta sẽ tìm hiểu cách sử dụng thư viện dart:convert để phân tích một cách thủ công các dữ liệu JSON. Đây là một thư viện tích hợp sẵn trong Dart và phù hợp với các dự án nhỏ.
Đối với các ứng dụng có nhiều mô hình JSON phức tạp hơn, việc sử dụng dart:convert có thể nhanh chóng trở lên tẻ nhạt, lặp đi lặp lại và dẫn đến nhiều lỗi nhỏ. Trong trường hợp đó bạn nên sử dụng thư viện dart_json_mapper hoặc json_serializable.
Mặc dù hiện tại có nhiều thư viện Dart JSON được cung cấp bởi cộng đồng, tuy nhiên nó không phong phú so với Java. Có thể bạn đặt ra câu hỏi "Có thư viện nào tương đương với GSON/Jackson/Moshi của Java không?", câu trả lời là có, đó là dart_json_mapper.
Là một thư viện đơn giản, dart:convert không cần bất kỳ một cấu hình bổ xung nào và là thư viện xử lý JSON đầu tiên mà bạn cần nghĩ tới, dành cho các dự án nhỏ.
Một vài hàm được cung cấp bởi thư viện dart:convert:
dynamic jsonDecode(String source,  {Object? reviver(Object? key, Object? value)?})
String jsonEncode(Object? object, {Object? toEncodable(Object? nonEncodable)?})

2. jsonDecode(..)

dynamic jsonDecode(String source,  {Object? reviver(Object? key, Object? value)?})
Hàm jsonDecode() được sử dụng để phân tích (parse) một văn bản JSON và trả về một đối tượng Dart. Hàm này trả về kiểu dynamic. Kiểu trả về này có thể là:
  • Map<String,dynamic>
  • List<dynamic>
  • Một đối tượng Dart nếu tham số reviver khác null (Có thể; xem một ví dụ bên dưới).
Các tham số:
  • source: Một văn bản có định dạng JSON.
  • reviver: Một hàm tuỳ chọn được gọi cho mỗi property tìm thấy trong quá trình phân tích văn bản JSON này. Tham số [key=null] tương ứng với đối tượng JSON toàn cục. Các property ở mức lá sẽ được thực thi đầu tiên, property ở mức gốc ở được thực thi cuối cùng.
Ví dụ: Hàm jsonDecode() trả về một Map<String,dynamic>:
json_jsonDecode_ex1.dart
import 'dart:convert';

void main() {
  var jsonString = '''{
        "name": "John Smith",
        "email": "john@example.com",
        "salary": 5000,
        "addresses": ["Address 1", "Address 2"]
      }''';  
  Map<String, dynamic> map = jsonDecode(jsonString);

  for (var key in map.keys) {
    print('$key --> ${map[key]}');
  }
  print(' --- ');
 
  List<dynamic> addresses =  map['addresses'];
  for(String address in addresses) {
     print('Address: $address');
  }
}
Output:
name --> John Smith
email --> john@example.com
salary --> 5000
addresses --> [Address 1, Address 2]
 ---
Address: Address 1
Address: Address 2
Ví dụ tiếp theo với JSON phức tạp hơn:
json_jsonDecode_ex2.dart
import 'dart:convert';

void main() {
  var jsonString = '''{
        "name": "John Smith",
        "email": "john@example.com",
        "children": [ {
            "name": "Jack Smith",
            "email": "jack@example.com"
        }, {
            "name": "Harry Smith",
            "email": "harry@example.com"
        }]
      }''';
  Map<String, dynamic> map = jsonDecode(jsonString);

  for (var key in map.keys) {
    print('$key --> ${map[key]}');
  }
  print(' --- ');

  List<dynamic> children = map['children'];
  for (dynamic child in children) {
    var childMap = child as Map<String, dynamic>;
    for (var k in childMap.keys) {
      print('  $k --> ${childMap[k]}');
    }
  }
}
Output:
name --> John Smith
email --> john@example.com
children --> [{name: Jack Smith, email: jack@example.com}, {name: Harry Smith, email: harry@example.com}]
 ---
  name --> Jack Smith
  email --> jack@example.com
  name --> Harry Smith
  email --> harry@example.com
Ví dụ: Hàm jsonDecode() trả về một List<dynamic>:
json_jsonDecode_ex2.dart
import 'dart:convert';
void main() {
  var jsonString = '''[ {
            "name": "Jack Smith",
            "email": "jack@example.com"
        }, {
            "name": "Harry Smith",
            "email": "harry@example.com"
        }]''';
  List<dynamic> list = jsonDecode(jsonString);

  for (var element in list) {
    var map = element as Map<String, dynamic>;
    for (var k in map.keys) {
      print('$k --> ${map[k]}');
    }
  }
}
Output:
name --> Jack Smith
email --> jack@example.com
name --> Harry Smith
email --> harry@example.com
Ví dụ: Sử dụng hàm jsonDecode() với tham số reviver để chuyển đổi một văn bản JSON thành một đối tượng Dart.
json_jsonDecode_reviver_ex1.dart
import 'dart:convert';

void main() {
  var jsonString = '''{
        "name": "John Smith",
        "email": "john@example.com",
        "contact": {
           "address": "Address 1",
           "phone": "12345"
        }  
      }''';

  Employee emp = jsonDecode(jsonString, reviver: (k, v) {
    if (v is Map) {
      if (k == 'contact') {
        var contactRaw = v as Map<String, dynamic>;
        return Contact.fromRaw(contactRaw);
      } else {
        // k == null
        var empRaw = v as Map<String, dynamic>;
        return Employee.fromRaw(empRaw);
      }
    }
    return v;
  });

  print('Emp Name: ${emp.name}');
  print('Emp Email: ${emp.email}');
  print('Address: ${emp.contact.address}');
}

class Contact {
  String address;
  String phone;
  Contact(this.address, this.phone); // Constructor
  Contact.fromRaw(Map<String, dynamic> map) // Constructor
      : address = map['address'],
        phone = map['phone'];
}

class Employee {
  String name;
  String email;
  Contact contact;
  Employee(this.name, this.email, this.contact); // Constructor
  Employee.fromRaw(Map<String, dynamic> map) // Constructor
      : name = map['name'],
        email = map['email'],
        contact = map['contact'];
}
Output:
Emp Name: John Smith
Emp Email: john@example.com
Address: Address 1

3. jsonEncode(..)

String jsonEncode(Object? object, {Object? toEncodable(Object? nonEncodable)?})
Hàm jsonEncode() được sử dụng để chuyển đổi một đối tượng Dart thành một văn bản JSON.
Các tham số:
  • object: Một đối tượng Dart.
  • toEncodable: Một hàm tuỳ chọn được sử dụng để chuyển đổi các đối tượng Dart không thể mã hoá (Non Encodable) thành các đối tượng có thể mã hoá (Encodable). Nếu tham số này không được cung cấp, hàm toJson() sẽ được sử dụng như một sự thay thế.
Ví dụ: Một đối tượng Dart với tất cả các property có thể mã hoá (Encodable):
// An Encodable object:
var employee = {
  'name': 'John Smith',
  'email': 'john@example.com',
  'contact': {
    'address': 'Address 1',
    'phone': '12345'}
};
Ví dụ: Một đối tượng Dart với một vài property có thể mã hoá, và một property không thể mã hoá:
var employee = {
  'name': 'John Smith', // Encodable
  'email': 'john@example.com', // Encodable
  'contact': Contact('Address 1', '12345') // Unencodable!!!
};
Ví dụ: Sử dụng hàm jsonEncode() để chuyển một đối tượng Dart thành văn bản JSON:
json_jsonEncode_ex1.dart
import 'dart:convert';

void main() {
  // An Object (Looks like a JSON):
  var employee = {
    'name': 'John Smith',
    'email': 'john@example.com',
    'contact': {
      'address': 'Address 1',
      'phone': '12345'}
  };
  var jsonString = jsonEncode(employee);
  print(jsonString);
}
Output:
{"name":"John Smith","email":"john@example.com","contact":{"address":"Address 1","phone":"12345"}}
Ví dụ: Chuyển đổi một đối tượng Map thành văn bản JSON:
json_jsonEncode_ex2.dart
import 'dart:convert';

void main() {
  var map = Map<String,dynamic>();
    
  map['name'] = 'John Smith';
  map['email'] = 'john@example.com';

  var jsonString = jsonEncode(map);
  print(jsonString);
}
Output:
{"name":"John Smith","email":"john@example.com"}
Ví dụ: Sử dụng hàm jsonEncode() với tham số toEncodable:
json_jsonEncode_toEncodable_ex1.dart
import 'dart:convert';
void main() {
  var contact = Contact('Address 1', '12345');
  var employee = {
    'name': 'John Smith', // Encodable
    'email': 'john@example.com', // Encodable
    'contact': contact // Un-encodable!!!
  };
  var jsonString = jsonEncode(employee, toEncodable: (nonEncodable) {
    if (nonEncodable is Contact) {
      return {
        'address': nonEncodable.address,
        'phone': nonEncodable.phone
      };
    }
    return null;
  });
  print(jsonString);
}

class Contact {
  String address;
  String phone;
  Contact(this.address, this.phone); // Constructor
}
Output:
{"name":"John Smith","email":"john@example.com","contact":{"address":"Address 1","phone":"12345"}}
Ví dụ: Sử dụng hàm jsonEncode() với tham số toEncodable:
json_jsonEncode_toEncodable_ex2.dart
import 'dart:convert';

void main() {
  var contact = Contact('Address 1', '12345');
  var employee = Employee('John Smith', 'john@example.com', contact);

  var jsonString = jsonEncode(employee, toEncodable: (nonEncodable) {
    if (nonEncodable is Contact) {
      return {
        'address': nonEncodable.address,
        'phone': nonEncodable.phone
      };
    } else if(nonEncodable is Employee) {
       return {
           'name': nonEncodable.name,
           'email': nonEncodable.email,
           'contact': nonEncodable.contact
       };
    }
  });
  print(jsonString);
}

class Contact {
  String address;
  String phone;
  Contact(this.address, this.phone); // Constructor
}

class Employee {
  String name;
  String email;
  Contact contact;
  Employee(this.name, this.email, this.contact); // Constructor
}