lib | ||
test | ||
tool | ||
.analysis-options | ||
.gitignore | ||
.travis.yml | ||
LICENSE | ||
pubspec.yaml | ||
README.md |
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
In your pubspec.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
.
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:
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
:
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
:
// 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<String, dynamic> 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.
@serializable
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
:
@serializable
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
):
@serializable
abstract class _Author extends Model {
List<_Book> books;
@Alias('newest_book')
_Book newestBook;
Map<String, _Book> booksByIsbn;
}