Cristian Garcia
Cristian Garcia

Reputation: 9859

State of Serialization and Deserialization of JSON in Dart

I've had a good experience with serialization on C#, and after searching and testing some Dart libraries I feel there isn't a really satisfactory answer in general.

  1. Id like to know the current state of Serialization/Deserialization of JSON in Dart?
  2. What should we expect in the future?
  3. Will this be eventually supported by the language itself?
  4. What are currently the best practices?

Id also like anybody that reads this to please post any new information, even if the post gets old.

Upvotes: 3

Views: 1942

Answers (7)

DMJ
DMJ

Reputation: 854

I realize this is an old question, but if you're coming here in 2019+ there is an excellent code-generation solution I've found:

https://pub.dartlang.org/packages/json_serializable

Judging by the git-hub repository I'd say this is the "official" solution as well.

It works using the annotations @JsonSerializable and @JsonKey to control serialization. In my experience it seems to flawlessly handle inheritance and the like as well. It automatically generates serialization and decentralization functions when you build the project.

Upvotes: 3

David Morgan
David Morgan

Reputation: 486

Generally, there is a move away from mirrors-based solutions to codegen-based solutions, particularly based on package:source_gen. This is because codegen can provider smaller and faster runtimes than mirrors.

One package that uses codegen for serialization is built_value:

https://github.com/google/built_value.dart

With built_value your model classes look like this:

abstract class Account implements Built<Account, AccountBuilder> {
  static Serializer<Account> get serializer => _$accountSerializer;

  int get id;
  String get name;
  BuiltMap<String, JsonObject> get keyValues;

  factory Account([updates(AccountBuilder b)]) = _$Account;
  Account._();
}

Note that built_value isn't just about serialization -- it also provides operator==, hashCode, toString, and a builder class.

Upvotes: 1

TheAJ
TheAJ

Reputation: 10875

Dart has an implementation to encode and decode Maps, Lists, and primitive types. You can find examples on this article. If you're looking for speed, this is probably the fastest, as they implement the json conversion in native C/C++ - libraries made by authors are usually written in Dart, and will be slower.

The disadvantage of the JSON.encode and JSON.decode is that they can't take any other Objects besides the ones mentioned above without having the toJson and fromJson methods.

Fortunately, there's libraries that take advantage of reflection in Dart to make it easier. I made a small library myself, to serialize and deserialize objects to and from JSON without any extra code to your classes. You can find it here. In addition to the above solutions to your issue, there's many you can find on the Dart pub website.

Upvotes: 0

luizmineo
luizmineo

Reputation: 966

Currently, you can use redstone_mapper to convert between Dart objects and JSON. This package is a plugin to the Redstone.dart framework, but can be used without it. There's also other options available on Pub

Upvotes: 2

Cristian Garcia
Cristian Garcia

Reputation: 9859

I am currently serializing with exportable and deserializing with morph.

Upvotes: 0

Danny Tuppeny
Danny Tuppeny

Reputation: 42343

For now, the best option is probably to use the Smoke library.

It's a subset of the Mirrors functionality but has both a Mirrors-based and a Codegen-based implementation. It's written by the PolymerDart team, so it's as close to "Official" as we're going to get.

While developing, it'll use the Mirrors-based encoding/decoding; but for publishing you can create a small transformer that will generate code.

Seth Ladd created a code sample here, which I extended slightly to support child-objects:

abstract class Serializable {
  static fromJson(Type t, Map json) {
    var typeMirror = reflectType(t);
    T obj = typeMirror.newInstance(new Symbol(""), const[]).reflectee;
    json.forEach((k, v) {
      if (v is Map) {
        var d = smoke.getDeclaration(t, smoke.nameToSymbol(k));
        smoke.write(obj, smoke.nameToSymbol(k), Serializable.fromJson(d.type, v));
      } else {
        smoke.write(obj, smoke.nameToSymbol(k), v);
      }
    });
    return obj;
  }

  Map toJson() {
    var options = new smoke.QueryOptions(includeProperties: false);
    var res = smoke.query(runtimeType, options);
    var map = {};
    res.forEach((r) => map[smoke.symbolToName(r.name)] = smoke.read(this, r.name));
    return map;
  }
}

Currently, there is no support to get generic type information (eg. to support List) in Smoke; however I've raised a case about this here:

https://code.google.com/p/dart/issues/detail?id=20584

Until this issue is implemented, a "good" implementation of what you want is not really feasible; but I'm hopeful it'll be implemented soon; because doing something as basic as JSON serialisation kinda hinges on it!

Alan Knight is also working on a Serialisation package, however I found it to lack support for things as simple as converting datetimes to strings, and the solution seemed rather verbose for something so basic.

For now, in my own project, I've gone with codegenning our json serialisation (in the form of toMap and fromMap methods) since we would already have C# versions of our classes for the server side. If time allows, I'd like to tidy those code up and make a NuGet package (it supports nested objects, arrays, excluding properties, etc.).

Upvotes: 4

G&#252;nter Z&#246;chbauer
G&#252;nter Z&#246;chbauer

Reputation: 657376

There is no "one size fits all" serialization solution. For a lengthy discussion see https://groups.google.com/a/dartlang.org/forum/#!searchin/misc/serialization/misc/0pv-Uaq8FGI/5iMrzOrlUKwJ

Upvotes: 1

Related Questions