Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSON serialization and deserialization to objects in Flutter

Since Flutter took out dart: mirrors off of its SDK, it's no longer possible to use libraries like dartson for JSON to object serialization/deserialization. However I've read that built_value is another way of achieving a similar purpose. I couldn't find any good examples on how to implement it as it contains a significant amount of boilerplate code. Can someone give me an example? For instance, this is the JSON I'm trying to serialize to objects:

{
    "name":"John",
    "age":30,
    "cars": [
        { "name":"Ford", "models":[ "Fiesta", "Focus", "Mustang" ] },
        { "name":"BMW", "models":[ "320", "X3", "X5" ] },
        { "name":"Fiat", "models":[ "500", "Panda" ] }
    ]
 }
like image 801
user3217522 Avatar asked Jun 16 '17 15:06

user3217522


People also ask

What is JSON and serialization in flutter?

JSON serialization with code generation means having an external library generate the encoding boilerplate for you. After some initial setup, you run a file watcher that generates the code from your model classes. For example, json_serializable and built_value are these kinds of libraries.

What is JSON serialization Dart?

The JSON (JavaScript Object Notation) is a kind of data format that encodes an object into a string. This kind of data can be easily translated between server and browser, and server to server. Serialization is a process that converts an object into the same string.


1 Answers

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

like image 51
user3217522 Avatar answered Sep 30 '22 10:09

user3217522