JSON serialization and deserialization to objects in Flutter JSON serialization and deserialization to objects in Flutter dart dart

JSON serialization and deserialization to objects in Flutter


I was hoping for more details from the answers provided. Even though they were good suggestions, they were too general for me to understand. So after doing my own research, I'll share my implementation to the above JSON example I provided in hope that it would save someone's else's time. So here are the steps I followed:

  • In my Flutter project, first I imported the following libraries:

dependencies:

built_value: ^1.0.1
built_collection: ^1.0.0

dev_dependencies:

build_runner: ^0.3.0
built_value_generator:^1.0.1

  • I created a folder called tool. In it, I put 2 files: build.dart and watch.dart. There implementations of those files are show below

build.dart

// Copyright (c) 2015, Google Inc. Please see the AUTHORS file for details.// All rights reserved. Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.import 'dart:async';import 'package:build_runner/build_runner.dart';import 'package:built_value_generator/built_value_generator.dart';import 'package:source_gen/source_gen.dart';/// Example of how to use source_gen with [BuiltValueGenerator].////// Import the generators you want and pass them to [build] as shown,/// specifying which files in which packages you want to run against.Future main(List<String> args) async {  await build(      new PhaseGroup.singleAction(          new GeneratorBuilder([new BuiltValueGenerator()]),          new InputSet('built_value_example', const [            'lib/model/*.dart',            'lib/*.dart',          ])),      deleteFilesByDefault: true);}

watch.dart

// Copyright (c) 2016, Google Inc. Please see the AUTHORS file for details.// All rights reserved. Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.import 'dart:async';import 'package:build_runner/build_runner.dart';import 'package:built_value_generator/built_value_generator.dart';import 'package:source_gen/source_gen.dart';/// Example of how to use source_gen with [BuiltValueGenerator].////// This script runs a watcher that continuously rebuilds generated source.////// Import the generators you want and pass them to [watch] as shown,/// specifying which files in which packages you want to run against.Future main(List<String> args) async {  watch(      new PhaseGroup.singleAction(          new GeneratorBuilder([new BuiltValueGenerator()]),          new InputSet('built_value_example', const [            'lib/model/*.dart',            'lib/*.dart'])),      deleteFilesByDefault: true);}
  • I created a serializers.dart file that would serialize my json string to my custom dart object, and my model object person.dart

serializers.dart

library serializers;import 'package:built_collection/built_collection.dart';import 'package:built_value/serializer.dart';import 'package:built_value/standard_json_plugin.dart';import 'model/person.dart';part 'serializers.g.dart';Serializers serializers = (    _$serializers.toBuilder()..addPlugin(new StandardJsonPlugin())).build();

person.dart

library person;import 'package:built_collection/built_collection.dart';import 'package:built_value/built_value.dart';import 'package:built_value/serializer.dart';part 'person.g.dart';abstract class Person implements Built<Person, PersonBuilder> {  String get name;  int get age;  BuiltList<Car> get cars;  Person._();  factory Person([updates(PersonBuilder b)]) = _$Person;  static Serializer<Person> get serializer => _$personSerializer;}abstract class Car implements Built<Car, CarBuilder> {  String get name;  BuiltList<String> get models;  Car._();  factory Car([updates(CarBuilder b)]) = _$Car;  static Serializer<Car> get serializer => _$carSerializer;}
  • After creating the 4 files above, it will show some compiler errors. Don't mind them yet. This is because the build.dart file hasn't been run yet. So in this step, run build.dart. If you're using Webstorm, simply right click on build.dart and hit "Run build.dart". This will create 2 files: "person.g.dart" and "serializers.g.dart". If you notice carefully, in our build.dart file, we put 'lib/model/.dart' and 'lib/.dart'. The build knows where to look for those files by going through the paths specified and looks for files which have part "something" included. So it's important to keep that line in those files before running the build.dart file

  • Finally, now I can use the serializer in my main.dart file to serialize the json string to my custom dart object class Person. In my main.dart, I added the following code in initState()

main.dart

  Person _person;  @override  void initState() {    super.initState();    String json = "{"        "\"name\":\"John\",\"age\":30,\"cars\": "        "["        "{ \"name\":\"Ford\", \"models\":[ \"Fiesta\", \"Focus\", \"Mustang\" ] },"        "{ \"name\":\"BMW\", \"models\":[ \"320\", \"X3\", \"X5\" ] },"        "{ \"name\":\"Fiat\", \"models\":[ \"500\", \"Panda\" ] }"        "]}";    setState(() {      _person = serializers.deserializeWith(          Person.serializer, JSON.decode(json));    });  }

My sample project is also available on Github Built value sample project


json_serialization

This package by the Dart Team generates everything needed for the fromJson constructor and toJson method in a seprate file.

Dependencies

Add the following dependencies:

dependencies:  json_annotation: ^2.0.0dev_dependencies:  build_runner: ^1.0.0  json_serializable: ^2.0.0

Model class

Adapt your model class to have the following parts:

import 'package:json_annotation/json_annotation.dart';// will be generated laterpart 'person.g.dart';@JsonSerializable()class Person {  Person(this.name, this.age);  final String name;  final int age;  factory Person.fromJson(Map<String, dynamic> json) =>      _$PersonFromJson(json);  Map<String, dynamic> toJson() => _$PersonToJson(this);}

Generate code

Generate the person.g.dart file from the terminal:

flutter packages pub run build_runner build

Use it

Then use it like this:

JSON → object

String rawJson = '{"name":"Mary","age":30}';Map<String, dynamic> map = jsonDecode(rawJson);Person person = Person.fromJson(map);

Object → JSON

Person person = Person('Mary', 30);Map<String, dynamic> map = person.toJson();String rawJson = jsonEncode(map);

Notes

  • In a Dart project use pub run build_runner build.
  • See this answer for more ways to serialize JSON.


From the Dart web site:

The dart:convert library provides a JsonCodec class, which you can use to convert simple types (map, list, int, num, string) automatically from a and to a JSON string. The two key static methods are JSON.encode(object) and JSON.decode(string).

Decoding example:

import 'dart:convert';...    Map<String, dynamic> parsedMap = JSON.decode(json);print(parsedMap['name']); // Johnprint(parsedMap['age']); // 30

Encoding example:

Map<String, dynamic> mapData = <String, dynamic>{ 'hello': 'world!' };String jsonData = JSON.encode(mapData); // convert map to String

If you want to have your JSON inflate into custom Dart classes instead of a tree of primitive objects, Hadrien's answer should point you in the right direction, but I just wanted to leave this here in case anyone else is trying to get basic JSON serialization/deserialization working.