# serialize [![Pub](https://img.shields.io/pub/v/angel_serialize.svg)](https://pub.dartlang.org/packages/angel_serialize) [![build status](https://travis-ci.org/angel-dart/serialize.svg)](https://travis-ci.org/angel-dart/serialize) **This project is currently in the early stages, and may change at any given time without warning.** Source-generated serialization for Dart object. This package uses `package:source_gen` to eliminate the time you spend writing boilerplate serialization code for your models. `package:angel_serialize` also powers `package:angel_postgres` and other ORM functionality. * [Usage](#usage) * [Models](#models) * [`@Alias(...)`](#aliases) * [`@exclude`](#excluding-keys) * [Nesting](#nesting) # Usage In your `pubspec.yaml`: ```yaml dependencies: angel_serialize: git: https://github.com/angel-dart/serialize.git dev_dependencies: build_runner: ^0.3.0 ``` You'll want to create a Dart script, usually named `tool/phases.dart` that invokes the `JsonModelGenerator`. ```dart import 'package:build_runner/build_runner.dart'; import 'package:source_gen/source_gen.dart'; import 'package:angel_serialize/builder.dart'; final PhaseGroup PHASES = new PhaseGroup.singleAction( new GeneratorBuilder([const JsonModelGenerator()]), new InputSet('[YOUR_PACKAGE_NAME_HERE]', const ['lib/src/models/*.dart'])); ``` And then, a `tool/build.dart` can build your serializers: ```dart import 'package:build_runner/build_runner.dart'; import 'phases.dart'; main() => build(PHASES, deleteFilesByDefault: true); ``` If you want to watch for file changes and re-build when necessary, replace the `build` call with a call to `watch`. They take the same parameters. # Models There are a few changes opposed to normal Model classes. You need to add a `@serializable` annotation to your model class to have it serialized, and a serializable model class's name should also start with a leading underscore. In addition, you may consider using an `abstract` class. Rather you writing the public class, `angel_serialize` does it for you. This means that the main class can have its constructors automatically generated, in addition into serialization functions. For example, say we have a `Book` model. Create a class named `_Book`: ```dart library angel_serialize.test.models.book; import 'package:angel_framework/common.dart'; import 'package:angel_serialize/angel_serialize.dart'; part 'book.g.dart'; @serializable abstract class _Book extends Model { @override String id; String author, title, description; @Alias('page_count') int pageCount; @override DateTime createdAt, updatedAt; } ``` The following will be generated in `book.g.dart`: ```dart // GENERATED CODE - DO NOT MODIFY BY HAND part of angel_serialize.test.models.book; // ************************************************************************** // Generator: JsonModelGenerator // Target: abstract class _Book // ************************************************************************** class Book extends _Book { @override String id; @override String author; @override String title; @override String description; @override int pageCount; @override DateTime createdAt; @override DateTime updatedAt; Book( {this.id, this.author, this.title, this.description, this.pageCount, this.createdAt, this.updatedAt}); factory Book.fromJson(Map data) { return new Book( id: data['id'], author: data['author'], title: data['title'], description: data['description'], pageCount: data['page_count'], createdAt: data['createdAt'] is DateTime ? data['createdAt'] : (data['createdAt'] is String ? DateTime.parse(data['createdAt']) : null), updatedAt: data['updatedAt'] is DateTime ? data['updatedAt'] : (data['updatedAt'] is String ? DateTime.parse(data['updatedAt']) : null)); } Map toJson() => { 'id': id, 'author': author, 'title': title, 'description': description, 'page_count': pageCount, 'createdAt': createdAt == null ? null : createdAt.toIso8601String(), 'updatedAt': updatedAt == null ? null : updatedAt.toIso8601String() }; static Book parse(Map map) => new Book.fromJson(map); } ``` ## Aliases Whereas Dart fields conventionally are camelCased, most database columns tend to be snake_cased. This is not a problem, because we can define an alias for a field. ```dart abstract class _Spy extends Model { /// Will show up as 'agency_id' in serialized JSON. /// /// When deserializing JSON, instead of searching for an 'agencyId' key, /// it will use 'agency_id'. /// /// Hooray! @Alias('agency_id') String agencyId; } ``` ## Excluding Keys In pratice, there may keys that you want to exclude from JSON. To accomplish this, simply annotate them with `@exclude`: ```dart abstract class _Whisper extends Model { /// Will never be serialized to JSON @exclude String secret; } ``` # Nesting `angel_serialize` also supports a few types of nesting of `@serializable` classes: * As a class member * As the type argument to a `List` * As the second type argument to a `Map` In other words, the following are all legal, and will be serialized/deserialized. Be sure to use the underscored name of a child class (ex. `_Book`): ```dart @serializable abstract class _Author extends Model { List<_Book> books; @Alias('newest_book') _Book newestBook; Map booksByIsbn; } ```