enough_serialization

Last updated:

0 purchases

enough_serialization Image
enough_serialization Images
Add to Cart

Description:

enough serialization

Serialize to and deserialize from JSON in runtime.
This pure Dart library does not depend on build time code generation.
Installation #
Add this dependency your pubspec.yaml file:
dependencies:
enough_serialization: ^1.4.0
copied to clipboard
The latest version or enough_serialization is .
Usage #
You can choose between two serialization modes:

Extend SerializableObject or implement Serializable for full control and complex cases. You have to store your field values in a dynamic map, however.
Implement OnDemandSerializable to only write and read your field values to/from a dynamic map when needed. This comes with limitations when having deep nested structures - in that case any serialization names of complex fields must be unique.

Serialization with Serializable and SerializableObject #
The easiest way is

extend SerializableObject
define a get and set field for each supported attribute and retrieve value from / store values to the attributes map.
if you have nested objects such as lists, maps or other serializable objects, define a function that creates new object instances for the corresponding attribute name in the objectCreators field.
if you want to store other values such as an enum, register a transformation function in the transformer field. This can also be done for map keys and for map/list values.

Simple Example
When you have only basic fields such as String, int, double, bool the usage is straight forward:
import 'package:enough_serialization/enough_serialization.dart';

class SimpleArticle extends SerializableObject {
String get name => attributes['name'];
set name(String value) => attributes['name'] = value;

int get price => attributes['price'];
set price(int value) => attributes['price'] = value;

double get popularity => attributes['popularity'];
set popularity(double value) => attributes['popularity'] = value;
}

void main() {
final article = SimpleArticle()
..name = 'Remote Control'
..price = 2499
..popularity = 0.1;
final serializer = Serializer();
final json = serializer.serialize(article);
print('serialized article: $json');

final inputJson =
'{"name": "Remote Control", "price": 2499, "popularity": 0.1}';
final deserializedArticle = SimpleArticle();
serializer.deserialize(inputJson, deserializedArticle);
print('name: ${deserializedArticle.name}');
print('price: ${deserializedArticle.price}');
print('popularity: ${deserializedArticle.popularity}');
}
copied to clipboard
Enum Example
Enumerations cannot be serialized or deserialized automatically. To support enum fields, register a transformer function:
transformers['area'] = (value) =>
value is ArticleArea ? value.index : ArticleArea.values[value];
copied to clipboard
Here's a complete example:
enum ArticleArea { electronics, music }

class ArticleWithEnum extends SerializableObject {
ArticleWithEnum() {
transformers['area'] = (value) =>
value is ArticleArea ? value.index : ArticleArea.values[value];
}

ArticleArea get area => attributes['area'];
set area(ArticleArea value) => attributes['area'] = value;

String get name => attributes['name'];
set name(String value) => attributes['name'] = value;
}

void main() {
final article = ArticleWithEnum()
..area = ArticleArea.electronics
..name = 'Remote Control';
final serializer = Serializer();
final json = serializer.serialize(article);
print('serialized article: $json');

final inputJson = '{"area": 0, "name": "Remote Control"}';
final deserializedArticle = ArticleWithEnum();
serializer.deserialize(inputJson, deserializedArticle);
print('area: ${deserializedArticle.area}');
print('name: ${deserializedArticle.name}');
}
copied to clipboard
Lists and Nested Serializable Objects
When you have nested objects, register a creation function in the objectCreators field. For nested maps and objects this function
receives a Map<String,dynamic> parameter with the values of the nested child object. If needed, you can evaluate
these values to determine which kind of object you need to create:
// create a list:
objectCreators['articles'] = (map) => <Article>[];
// create a nested simple object:
objectCreators['band'] = (map) => Band();
// created a nested complex field in a list:
objectCreators['articles.value'] = (map) {
final int areaIndex = map['area'];
final area = ArticleArea.values[areaIndex];
switch (area) {
case ArticleArea.electronics:
return ElectronicsArticle();
case ArticleArea.music:
return MusicArticle();
}
return Article();
};
copied to clipboard
Here's a complete example with nested objects and complex list elements:
enum ArticleArea { electronics, music }

class Article extends SerializableObject {
Article() {
transformers['area'] = (value) =>
value is ArticleArea ? value.index : ArticleArea.values[value];
}

ArticleArea get area => attributes['area'];
set area(ArticleArea value) => attributes['area'] = value;

String get name => attributes['name'];
set name(String value) => attributes['name'] = value;

int get price => attributes['price'];
set price(int value) => attributes['price'] = value;
}

class ElectronicsArticle extends Article {
ElectronicsArticle() {
area = ArticleArea.electronics;
}

String get recommendation => attributes['recommendation'];
set recommendation(String value) => attributes['recommendation'] = value;
}

class MusicArticle extends Article {
MusicArticle() {
area = ArticleArea.music;
objectCreators['band'] = (map) => Band();
}

Band get band => attributes['band'];
set band(Band value) => attributes['band'] = value;
}

class Band extends SerializableObject {
String get name => attributes['name'];
set name(String value) => attributes['name'] = value;

int get year => attributes['year'];
set year(int value) => attributes['year'] = value;

Band({String name, int year}) {
this.name = name;
this.year = year;
}
}

class Order extends SerializableObject {
Order() {
objectCreators['articles'] = (map) => <Article>[];
objectCreators['articles.value'] = (map) {
final int areaIndex = map['area'];
final area = ArticleArea.values[areaIndex];
switch (area) {
case ArticleArea.electronics:
return ElectronicsArticle();
case ArticleArea.music:
return MusicArticle();
}
return Article();
};
}

List<Article> get articles => attributes['articles'];
set articles(List<Article> value) => attributes['articles'] = value;
}

void main() {
final order = Order()
..articles = [
ElectronicsArticle()
..name = 'CD Player'
..price = 3799
..recommendation = 'Consider our streaming option, too!',
ElectronicsArticle()
..name = 'MC Tape Deck'
..price = 12399
..recommendation = 'Old school, like it!',
MusicArticle()
..name = 'The white album'
..price = 1899
..band = Band(name: 'Beatles', year: 1962)
];
final serializer = Serializer();
final json = serializer.serialize(order);
print('order: $json');

final inputJson =
'{"articles": [{"area": 0, "name": "CD Player", "price": 3799, "recommendation": "Consider our streaming option, too!"}, '
'{"area": 0, "name": "MC Tape Deck", "price": 12399, "recommendation": "Old school, like it!"}, '
'{"area": 1, "name": "The white album", "price": 1899, "band": {"name": "Beatles", "year": 1962}}]}';
final deserializedOrder = Order();
serializer.deserialize(inputJson, deserializedOrder);
for (var i = 0; i < deserializedOrder.articles.length; i++) {
final article = deserializedOrder.articles[i];
print('$i: area: ${article.area}');
print('$i: name: ${article.name}');
print('$i: price: ${article.price}');
if (article is ElectronicsArticle) {
print('$i: recommendation: ${article.recommendation}');
} else if (article is MusicArticle) {
print('$i: band-name: ${article.band.name}');
print('$i: band-year: ${article.band.year}');
}
}
}
copied to clipboard
Nested Maps
When nesting maps, you also register your creator function in the objectCreators, e.g.
objectCreators['news-by-year'] = (map) => <int, String>{};
copied to clipboard
When dealing with maps with non-String keys, you need to transform these to Strings and back to their original
form when deserializing. As for enums you do this by registering a transformer function that receives the value.
You registers the function under the field name with a .key appended to it:
transformers['news-by-year.key'] =
(value) => value is int ? value.toString() : int.parse(value);
copied to clipboard
Same as for lists, you can also register objectCreators and transformers for map values by appending a .value to the field's serialization name.
Here is a complete example for serializing an object with an embedded map:
class MappedArticle extends SerializableObject {
MappedArticle() {
objectCreators['news-by-year'] = (map) => <int, String>{};
transformers['news-by-year.key'] =
(value) => value is int ? value.toString() : int.parse(value);
}

String get name => attributes['name'];
set name(String value) => attributes['name'] = value;

Map<int, String> get newsByYear => attributes['news-by-year'];
set newsByYear(Map<int, String> value) => attributes['news-by-year'] = value;
}

void main() {
final newsByYear = {
2020: 'Corona, Corona, Corona...',
2021: 'The end of a pandemia',
2022: 'Climate change getting really serious'
};
final article = MappedArticle()
..name = 'My Article'
..newsByYear = newsByYear;
final serializer = Serializer();
final json = serializer.serialize(article);
print('article with map: $json');

final inputJson =
'{"name": "My Article", "news-by-year": {"2020": "Corona, Corona, Corona...", "2021": "The end of a pandemic", "2022": "Climate change getting really serious"}}';
final deserializedArticle = MappedArticle();
serializer.deserialize(inputJson, deserializedArticle);
print('article: ${article.name}');
for (final key in article.newsByYear.keys) {
print('$key: ${article.newsByYear[key]}');
}
}
copied to clipboard
On Demand Serialization #
Using a dynamic map for storing and retrieving fields requires you to create boiler-plate code and makes accessing fields slower.
When you want to use normal fields, you can implement OnDemandSerializable instead:
class Article implements OnDemandSerializable {
int price;
String name;


@override
void write(Map<String, dynamic> attributes) {
attributes['price'] = price;
attributes['name'] = name;
}

@override
void read(Map<String, dynamic> attributes) {
price = attributes['price'];
name = attributes['name'];
}
copied to clipboard
Use Serializer.serializeOnDemand(OnDemandSerializable) to create the JSON and Serializer.deserializeOnDemand(String,OnDemandSerializable)
to deserialize your classes.
In these calls you can optionally provide transformers and objectCreators to handle more complex scenarios like enums, other nested OnDemandSerializable, List or Map fields. The registration is the same as for Serializable, however you have can only register these special cases at that point. This means that field names of special cases must be unique throughout your object's hierarchy.
Here's a complete example of a complex structure with OnDemandSerializable:
class OnDemandArticle implements OnDemandSerializable {
String name;
Map<int, String> newsByYear;

String serialize() {
final serializer = Serializer();
final json = serializer.serializeOnDemand(
this,
transformers: {
'news-by-year.key': (value) =>
value is int ? value.toString() : int.parse(value),
},
);
return json;
}

void deserialize(String json) {
final serializer = Serializer();
serializer.deserializeOnDemand(
json,
this,
transformers: {
'news-by-year.key': (value) =>
value is int ? value.toString() : int.parse(value),
},
objectCreators: {
'news-by-year': (map) => <int, String>{},
},
);
}

@override
void write(Map<String, dynamic> attributes) {
attributes['name'] = name;
attributes['news-by-year'] = newsByYear;
}

@override
void read(Map<String, dynamic> attributes) {
name = attributes['name'];
newsByYear = attributes['news-by-year'];
}
}

void main() {
final newsByYear = {
2020: 'Corona, Corona, Corona...',
2021: 'The end of a pandemia',
2022: 'Climate change getting really serious'
};
final article = OnDemandArticle()
..name = 'My Article'
..newsByYear = newsByYear;
final json = article.serialize();
print('on demand article: $json');

final inputJson =
'{"name": "My Article", "news-by-year": {"2020": "Corona, Corona, Corona...", "2021": "The end of a pandemic", "2022": "Climate change getting really serious"}}';
final deserializedArticle = OnDemandArticle();
deserializedArticle.deserialize(inputJson);
print('deserialized article: ${article.name}');
for (final key in article.newsByYear.keys) {
print('$key: ${article.newsByYear[key]}');
}
}
copied to clipboard
Features and bugs #
Please file feature requests and bugs at the issue tracker.
Null-Safety #
enough_convert is null-safe from v1.3.0 onward.
License #
Licensed under the commercial friendly MIT License.

License:

For personal and professional use. You cannot resell or redistribute these repositories in their original state.

Files In This Product:

Customer Reviews

There are no reviews.