o7planning

Dart dart_json_mapper Tutorial with Examples

  1. dart_json_mapper
  2. Install the library
  3. Example
  4. Appendix

1. dart_json_mapper

dart_json_mapper is a library that provides a better solution than dart:convert for working with JSON data. It is suitable for applications with complex JSON models. However, to use it you need a few configuration steps. For small applications you should use the dart:convert library - it's simple and doesn't need any additional configuration.
The dart_json_mapper library inspired by json2typescript, serde, gson, feature parity with Java Jackson is very popular and has only four Annotations to remember to cover all possible use cases.
dart_json_mapper vs json_serializable
json_serializable is a better JSON handling library than dart:convert. However, it is only a semi-automatic library, and cannot be compared with the features that dart_json_mapper offers.
  • Dart json serializable

2. Install the library

To use the dart_json_mapper library, you need to declare it in the pubspec.yaml file:
pubspec.yaml
dependencies:
  dart_json_mapper:

dev_dependencies:
  build_runner:

3. Example

First, add the build.yaml file to your project. This is the configuration file, used to instruct build_runner to generate new source code files from the specified source code files.
build.yaml
targets:
  $default:
    builders:
      dart_json_mapper:
        generate_for:
          # here should be listed entry point files having 'void main()' function
          - lib/model/model.dart

      # This part is needed to tell original reflectable builder to stay away
      # it overrides default options for reflectable builder to an **empty** set of files
      reflectable:
        generate_for:
          - no/files
Next, create the Model classes:
dart_14139_dart_json_mapper (Your Project Name)
  - lib
      - model
           - model.dart
           - model_file1.dart
           - model_file2.dart
@jsonSerializable
This annotation is used for a class. The dart_json_mapper library will generate code to convert objects of this class to JSON and vice versa.
@JsonProperty
This Annotation is an option, used for class properties. It specifies the JSON property name that corresponds to a class property name if they are different.
@jsonSerializable
class Employee {
  @JsonProperty(name: 'employeeName') // JSON Property
  String name; // Dart Property 
  String email;
  ...
}
@jsonSerializable
class Employee { 
  @JsonProperty(ignore: true)
  String? privateEmail; // This property will be Ignored.
}
Use @JsonProperty(ignore:true) for a property to ignore it.
model_file1.dart: Contains the Contact and Employee classes, with rules for converting them to JSON structures and vice versa.
model_file1.dart
part of 'model.dart';

@jsonSerializable
class Contact {
  String address;
  String phone;

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

@jsonSerializable
class Employee {
  @JsonProperty(name: 'employeeName') // JSON Property Name!!
  String name; // Dart Property Name
  String email;
  Contact contact;

  @JsonProperty(ignore: true) 
  String? privateEmail; // This property will be Ignored.

  Employee(this.name, this.email, this.contact); // Constructor
}
model_file2.dart: Contains the Company class, with rules for converting it to JSON structures and vice versa.
model_file2.dart
part of 'model.dart';

@jsonSerializable
class Company {
  @JsonProperty(name: 'companyName') // JSON Property Name
  String name; // Dart Property Name
  Contact contact;

  Company(this.name, this.contact); // Constructor
}
  • The part and part of keywords in Dart
model.dart
import 'package:dart_json_mapper/dart_json_mapper.dart';

part 'model_file1.dart';
part 'model_file2.dart';

// This main() function is required!
void main() {
  // Empty
}
Open a Terminal window on the IDE:
  • View > Terminal (Visual Studio Code)
  • View > Tool Windows > Terminal (Android Studio)
Execute the command below to make dart_json_mapper generate extension code for Model classes.
dart run build_runner build --delete-conflicting-outputs
See the appendix at the end of the article if you receive an error when trying to run this command:
dart run build_runner build --delete-conflicting-outputs
dart run build_runner build --delete-conflicting-outputs
[INFO] Generating build script completed, took 415ms
[INFO] Reading cached asset graph completed, took 144ms
[INFO] Checking for updates since last build completed, took 768ms
[INFO] Running build completed, took 3.7s
[INFO] Caching finalized dependency graph completed, took 83ms
[INFO] Succeeded after 3.8s with 31 outputs (61 actions)
The tool generates you a Dart file. If there are any changes on the Model classes, run the above command again.
  • model.mapper.g.dart
Dart object ==> JSON:
This example shows you how to convert a Dart object to JSON text:
test_dart_to_json_ex1.dart
import 'package:dart_json_mapper/dart_json_mapper.dart';

import 'model/model.dart';
import 'model/model.mapper.g.dart';

void main() {
  initializeJsonMapper(); // <-----------------------

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

  var jsonString = JsonMapper.toJson(employee);
  print(jsonString);

  print(' --------------------------- ');

  contact = Contact('Address 1', '99999');
  var company = Company('Google', contact);
  jsonString = JsonMapper.toJson(company);

  print(jsonString);
}
Output:
{
 "employeeName": "John Smith",
 "email": "john@example.com",
 "contact": {
  "address": "Address 1",
  "phone": "12345"
 }
}
 ---------------------------
{
 "companyName": "Google",
 "contact": {
  "address": "Address 1",
  "phone": "99999"
 }
}
JSON ==> Dart object:
Next is an example that converts a JSON text to a Dart object:
test_json_to_dart_ex1.dart
import 'package:dart_json_mapper/dart_json_mapper.dart';

import 'model/model.dart';
import 'model/model.mapper.g.dart';

void main() {
  initializeJsonMapper(); // <-----------------------

  var jsonString1 = '''{
      "employeeName": "John Smith",
      "email": "john@example.com",
      "contact": {
        "address": "Address 1",
        "phone": "12345"
        }
      }''';

  // May be null:
  var employee = JsonMapper.fromJson<Employee>(jsonString1);
  print('Employee Phone: ${employee!.contact.phone}');

  print(' --------------------------- ');

  var jsonString2 = '''{
    "companyName": "Google",
    "contact": {
      "address": "Address 1",
      "phone": "99999"
      }
    }''';
  // May be null:
  var company = JsonMapper.fromJson<Company>(jsonString2);
  print('Company Phone: ${company!.contact.phone}');
}
Output:
Employee Phone: 12345
 ---------------------------
Company Phone: 99999
Map<String,dynamic> ==> Dart object:
test_map_to_dart_ex1.dart
import 'package:dart_json_mapper/dart_json_mapper.dart';

import 'model/model.dart';
import 'model/model.mapper.g.dart';

void main() {
  initializeJsonMapper(); // <-----------------------

  Map<String, dynamic> map1 = {
    "employeeName": "John Smith",
    "email": "john@example.com",
    "contact": {"address": "Address 1", "phone": "12345"}
  };

  // May be null:
  var employee = JsonMapper.fromMap<Employee>(map1);
  print('Employee Phone: ${employee!.contact.phone}');

  print(' --------------------------- ');

  Map<String, dynamic> map2 = {
    "companyName": "Google",
    "contact": {"address": "Address 1", "phone": "99999"}
  };
  // May be null:
  var company = JsonMapper.fromMap<Company>(map2);
  print('Company Phone: ${company!.contact.phone}');
}
Output:
Employee Phone: 12345
 --------------------------- 
Company Phone: 99999

4. Appendix

dart run build_runner build --delete-conflicting-outputs
If you receive an error when trying to run the above command, try the solution below:
If your project is DART:
  • File > Settings > Languages & Frameworks > Dart > Dart SDK path (Windows/Linux)
  • Android Studio > Settings > Languages & Frameworks > Dart > Dart SDK path (Mac)
Run:
/Volumes/Apps/Apps/dart-sdk/bin/dart run build_runner build --delete-conflicting-outputs
If your project is FLUTTER:
Run:
/Volumes/Apps/Apps/flutter/bin/dart run build_runner build --delete-conflicting-outputs