Skip to content

Repository files navigation

dynamo

A JSON serialization for object graphs. This library will not generate a simple JSON but add some information for types and references. Thus this library supports circle references, inheritance and object graphs (reference aware).

Dynamo uses source_gen to generate code, and has no dependency to the 'dart:mirror' at all.

Dynamo is rewritten from scratch, but influenced from Dartson (dartson on github), with some some extensions to Dartson.

Alternatives

If you need just simple JSON serialization you might use JsonSerializable from source_gen instead, or Dartson. Latter uses code transformers.

Annotations

Serializable Objects must be annotated with @DynamoSerializable(), and also must use a generated mixin (Namepattern is _$classnameDynamoMixin) Fields with missing getter or setter will be ignored. Optional fields can be annotated with @DynamoEntry() in order to use a different json key, or be ignored for serialization.

@DynamoSerializable()
classMemberextendsObjectwith_$MemberDynamoMixin {
int id =0;
String firstName;
@DynamoEntry(name:'last_name')
String lastName;
DateTime registered;
@DynamoEntry(ignore:true)
bool ignoreMe;
Member();
Member.withIdAndName(this.id, this.firstName, this.lastName) {}
// will be ignored (no setter)boolget isNew => id <1;
}

Generate Mixins

Build steps are needed to setup. See the source_gen > Running Generators and example.

Serialization

The root object for serialization (toJson) or deserialization (fromJson) might be:

  • a list,
  • a map,
  • a simple type (bool, num, String),
  • or a registered type (annotated with DynamoSerializable and using a generated DynamoMixin).

The protocol for serialization is:

StringtoJson(dynamic value);
dynamicfromJson(String json, {InstanceFactoryfactory});

Usually fromJson will detect the target instance but optional a factory can be passed instead.

type registration

Since no mirroring system will be used, each type must be registered using registerType with an identifier, the type and a factory for new instances:

newDynamo()
..registerType('member', Member, () =>newMember())

dynamo configuration

Different dynamo configurations might be used (with the same serializable objects) to produce different JSON output.

var dynamo1 =newDynamo()
..addTransformer(newMemberTypeTransformer())
..registerType('member', Member, () =>newMember())
..registerType('tag', Tag, () =>newTag())
;
var dynamo2 =newDynamo()
..registerType('member', Member, () =>newMember())
..registerType('tag', Tag, () =>newTag())
..addTransformer(newMemberTransformer(allMembers))
;

transformers

A type transformer can be added to a dynamo (configuration) e.g for mapping enum values, or just a representation for an entity.

Transformer sample: Enum mapping
enumMemberType { adult, student, unemployed, pensioner, child, vip }
@DynamoSerializable()
classMemberextendsObjectwith_$MemberDynamoMixin {
MemberType type;
Member();
}
classMemberTypeTransformerextendsTypeTransformer<MemberType> {
finalStringKEY='membertype';
finalMemberType defaultMemberType =MemberType.adult;
Map<String,MemberType> typeMap =const {
'adult':MemberType.adult,
'student':MemberType.student,
'unemployed':MemberType.unemployed,
'pensioner':MemberType.pensioner,
'child':MemberType.child,
'vip':MemberType.vip
};
@overrideboolcanDecode(value) => value isMemberType;
@overrideboolcanEncode(value) => value isMap&& value.containsKey(KEY);
dynamicencode(MemberType value) {
var type = value ==null? defaultMemberType : value;
for (var key in typeMap.keys) {
if (typeMap[key] == type) {
return {KEY: key};
}
}
thrownewArgumentError("unsupported type");
}
MemberTypedecode(dynamic value) => typeMap.containsKey(value[KEY]) ? typeMap[value[KEY]] : defaultMemberType;
}
main() {
var dynamo =newDynamo()
..addTransformer(newMemberTypeTransformer())
..registerType('member', Member, () =>newMember());
// dynamo.toJson(member);// dynamo.fromJson(member);
}
Transformer sample: Representation instead of whole mapped instance

E.g. if instances already known then only a representation (e.g. ID of an entity) can be serialized instead:

classMemberTransformerimplementsTypeTransformer<Member> {
staticconstStringKEY='memberId';
finalList<Member> members; // usually a repositoryMemberTransformer(this.members);
@overrideboolcanEncode(value) => value isMember;
@overrideencode(Member value) => {KEY: value.id};
@overrideboolcanDecode(value) => value isMap&& value.containsKey(KEY);
@overrideMemberdecode(value) => members.firstWhere((member) => member.id == value[KEY], orElse: () =>null);
}
// usually repositories for membersList<Member> members = [m1, m2, m3];
MemberTransformer memberTransformer =newMemberTransformer(members);
Dynamo dynamo =newDynamo()
..addTransformer(memberTransformer)
;
var output = dynamo.toJson(m2);

will produce:

 {"memberId":2}

datetime transformer

DateTime will be serialized automatically for fields but due to JSON restriction, can not be automatically detected if part of an untyped list oder map (only by guessing). If DateTime is used in untyped collections the bundled DateTimeTransformer can be used:

Dynamo dynamo =newDynamo()
..addTransformer(newDateTimeTransformer("_dt_"))
;

for values e.g. List values = [new DateTime.utc(2017,1,29), new DateTime.utc(2017,1,28)];

dynamo will produce

[
{"_dt_":"2017-01-29T00:00:00.000Z"},
{"_dt_":"2017-01-28T00:00:00.000Z"}
]

But now, also fields in registered type will use this transformer for DateTime fields:

{
"_isa_":"member",
"registered":{"_dt_":"2017-01-30T00:00:00.000Z"}
}

instead of (using internal datetime transformers for fields):

{
"_isa_":"member",
"registered":"2017-01-30T00:00:00.000Z"
}

generate pretty json output

classPrettyJsonCodecextendsJsonCodec {
JsonEncoderget encoder {
returnconstJsonEncoder.withIndent(' ');
}
}
newDynamo(codec:newPrettyJsonCodec()) ....

customize json keys for type and reference information

default keys:

  • typeKey: _isa_ (used to identify the type)
  • instanceIdKey: _id#_ (used to add a sequential number)
  • referenceKey: _ref_ (used to reference to a prior serialized instance)

Sample: serialize same instance (of type member) twice in a list:

[
{
"_isa_":"member",
"_id#_":1
},
{"_ref_":1}
]

To customize these key use following setters:

Dynamo dynamo =createCommonDynamo(JSON)
..typeKey =r"$typeof"
..instanceIdKey =r"$instance"
..referenceKey =r"$reference";

Same example will produce:

[
{
"$typeof":"member",
"$instance":1
},
{"$reference":1}
]

Example

See example of dynamo in Github Repo.

Not yet implemented

  • using different name for imported dynamo library (import as)

About

Dart JSON serialization for object graphs

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
GitHub - gerald24/dynamo: Dart JSON serialization for object graphs · GitHub
Skip to content

Repository files navigation

dynamo

A JSON serialization for object graphs. This library will not generate a simple JSON but add some information for types and references. Thus this library supports circle references, inheritance and object graphs (reference aware).

Dynamo uses source_gen to generate code, and has no dependency to the 'dart:mirror' at all.

Dynamo is rewritten from scratch, but influenced from Dartson (dartson on github), with some some extensions to Dartson.

Alternatives

If you need just simple JSON serialization you might use JsonSerializable from source_gen instead, or Dartson. Latter uses code transformers.

Annotations

Serializable Objects must be annotated with @DynamoSerializable(), and also must use a generated mixin (Namepattern is _$classnameDynamoMixin) Fields with missing getter or setter will be ignored. Optional fields can be annotated with @DynamoEntry() in order to use a different json key, or be ignored for serialization.

@DynamoSerializable()
classMemberextendsObjectwith_$MemberDynamoMixin {
int id =0;
String firstName;
@DynamoEntry(name:'last_name')
String lastName;
DateTime registered;
@DynamoEntry(ignore:true)
bool ignoreMe;
Member();
Member.withIdAndName(this.id, this.firstName, this.lastName) {}
// will be ignored (no setter)boolget isNew => id <1;
}

Generate Mixins

Build steps are needed to setup. See the source_gen > Running Generators and example.

Serialization

The root object for serialization (toJson) or deserialization (fromJson) might be:

  • a list,
  • a map,
  • a simple type (bool, num, String),
  • or a registered type (annotated with DynamoSerializable and using a generated DynamoMixin).

The protocol for serialization is:

StringtoJson(dynamic value);
dynamicfromJson(String json, {InstanceFactoryfactory});

Usually fromJson will detect the target instance but optional a factory can be passed instead.

type registration

Since no mirroring system will be used, each type must be registered using registerType with an identifier, the type and a factory for new instances:

newDynamo()
..registerType('member', Member, () =>newMember())

dynamo configuration

Different dynamo configurations might be used (with the same serializable objects) to produce different JSON output.

var dynamo1 =newDynamo()
..addTransformer(newMemberTypeTransformer())
..registerType('member', Member, () =>newMember())
..registerType('tag', Tag, () =>newTag())
;
var dynamo2 =newDynamo()
..registerType('member', Member, () =>newMember())
..registerType('tag', Tag, () =>newTag())
..addTransformer(newMemberTransformer(allMembers))
;

transformers

A type transformer can be added to a dynamo (configuration) e.g for mapping enum values, or just a representation for an entity.

Transformer sample: Enum mapping
enumMemberType { adult, student, unemployed, pensioner, child, vip }
@DynamoSerializable()
classMemberextendsObjectwith_$MemberDynamoMixin {
MemberType type;
Member();
}
classMemberTypeTransformerextendsTypeTransformer<MemberType> {
finalStringKEY='membertype';
finalMemberType defaultMemberType =MemberType.adult;
Map<String,MemberType> typeMap =const {
'adult':MemberType.adult,
'student':MemberType.student,
'unemployed':MemberType.unemployed,
'pensioner':MemberType.pensioner,
'child':MemberType.child,
'vip':MemberType.vip
};
@overrideboolcanDecode(value) => value isMemberType;
@overrideboolcanEncode(value) => value isMap&& value.containsKey(KEY);
dynamicencode(MemberType value) {
var type = value ==null? defaultMemberType : value;
for (var key in typeMap.keys) {
if (typeMap[key] == type) {
return {KEY: key};
}
}
thrownewArgumentError("unsupported type");
}
MemberTypedecode(dynamic value) => typeMap.containsKey(value[KEY]) ? typeMap[value[KEY]] : defaultMemberType;
}
main() {
var dynamo =newDynamo()
..addTransformer(newMemberTypeTransformer())
..registerType('member', Member, () =>newMember());
// dynamo.toJson(member);// dynamo.fromJson(member);
}
Transformer sample: Representation instead of whole mapped instance

E.g. if instances already known then only a representation (e.g. ID of an entity) can be serialized instead:

classMemberTransformerimplementsTypeTransformer<Member> {
staticconstStringKEY='memberId';
finalList<Member> members; // usually a repositoryMemberTransformer(this.members);
@overrideboolcanEncode(value) => value isMember;
@overrideencode(Member value) => {KEY: value.id};
@overrideboolcanDecode(value) => value isMap&& value.containsKey(KEY);
@overrideMemberdecode(value) => members.firstWhere((member) => member.id == value[KEY], orElse: () =>null);
}
// usually repositories for membersList<Member> members = [m1, m2, m3];
MemberTransformer memberTransformer =newMemberTransformer(members);
Dynamo dynamo =newDynamo()
..addTransformer(memberTransformer)
;
var output = dynamo.toJson(m2);

will produce:

 {"memberId":2}

datetime transformer

DateTime will be serialized automatically for fields but due to JSON restriction, can not be automatically detected if part of an untyped list oder map (only by guessing). If DateTime is used in untyped collections the bundled DateTimeTransformer can be used:

Dynamo dynamo =newDynamo()
..addTransformer(newDateTimeTransformer("_dt_"))
;

for values e.g. List values = [new DateTime.utc(2017,1,29), new DateTime.utc(2017,1,28)];

dynamo will produce

[
{"_dt_":"2017-01-29T00:00:00.000Z"},
{"_dt_":"2017-01-28T00:00:00.000Z"}
]

But now, also fields in registered type will use this transformer for DateTime fields:

{
"_isa_":"member",
"registered":{"_dt_":"2017-01-30T00:00:00.000Z"}
}

instead of (using internal datetime transformers for fields):

{
"_isa_":"member",
"registered":"2017-01-30T00:00:00.000Z"
}

generate pretty json output

classPrettyJsonCodecextendsJsonCodec {
JsonEncoderget encoder {
returnconstJsonEncoder.withIndent(' ');
}
}
newDynamo(codec:newPrettyJsonCodec()) ....

customize json keys for type and reference information

default keys:

  • typeKey: _isa_ (used to identify the type)
  • instanceIdKey: _id#_ (used to add a sequential number)
  • referenceKey: _ref_ (used to reference to a prior serialized instance)

Sample: serialize same instance (of type member) twice in a list:

[
{
"_isa_":"member",
"_id#_":1
},
{"_ref_":1}
]

To customize these key use following setters:

Dynamo dynamo =createCommonDynamo(JSON)
..typeKey =r"$typeof"
..instanceIdKey =r"$instance"
..referenceKey =r"$reference";

Same example will produce:

[
{
"$typeof":"member",
"$instance":1
},
{"$reference":1}
]

Example

See example of dynamo in Github Repo.

Not yet implemented

  • using different name for imported dynamo library (import as)

About

Dart JSON serialization for object graphs

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - gerald24/dynamo: Dart JSON serialization for object graphs · GitHub
Skip to content

Repository files navigation

dynamo

A JSON serialization for object graphs. This library will not generate a simple JSON but add some information for types and references. Thus this library supports circle references, inheritance and object graphs (reference aware).

Dynamo uses source_gen to generate code, and has no dependency to the 'dart:mirror' at all.

Dynamo is rewritten from scratch, but influenced from Dartson (dartson on github), with some some extensions to Dartson.

Alternatives

If you need just simple JSON serialization you might use JsonSerializable from source_gen instead, or Dartson. Latter uses code transformers.

Annotations

Serializable Objects must be annotated with @DynamoSerializable(), and also must use a generated mixin (Namepattern is _$classnameDynamoMixin) Fields with missing getter or setter will be ignored. Optional fields can be annotated with @DynamoEntry() in order to use a different json key, or be ignored for serialization.

@DynamoSerializable()
classMemberextendsObjectwith_$MemberDynamoMixin {
int id =0;
String firstName;
@DynamoEntry(name:'last_name')
String lastName;
DateTime registered;
@DynamoEntry(ignore:true)
bool ignoreMe;
Member();
Member.withIdAndName(this.id, this.firstName, this.lastName) {}
// will be ignored (no setter)boolget isNew => id <1;
}

Generate Mixins

Build steps are needed to setup. See the source_gen > Running Generators and example.

Serialization

The root object for serialization (toJson) or deserialization (fromJson) might be:

  • a list,
  • a map,
  • a simple type (bool, num, String),
  • or a registered type (annotated with DynamoSerializable and using a generated DynamoMixin).

The protocol for serialization is:

StringtoJson(dynamic value);
dynamicfromJson(String json, {InstanceFactoryfactory});

Usually fromJson will detect the target instance but optional a factory can be passed instead.

type registration

Since no mirroring system will be used, each type must be registered using registerType with an identifier, the type and a factory for new instances:

newDynamo()
..registerType('member', Member, () =>newMember())

dynamo configuration

Different dynamo configurations might be used (with the same serializable objects) to produce different JSON output.

var dynamo1 =newDynamo()
..addTransformer(newMemberTypeTransformer())
..registerType('member', Member, () =>newMember())
..registerType('tag', Tag, () =>newTag())
;
var dynamo2 =newDynamo()
..registerType('member', Member, () =>newMember())
..registerType('tag', Tag, () =>newTag())
..addTransformer(newMemberTransformer(allMembers))
;

transformers

A type transformer can be added to a dynamo (configuration) e.g for mapping enum values, or just a representation for an entity.

Transformer sample: Enum mapping
enumMemberType { adult, student, unemployed, pensioner, child, vip }
@DynamoSerializable()
classMemberextendsObjectwith_$MemberDynamoMixin {
MemberType type;
Member();
}
classMemberTypeTransformerextendsTypeTransformer<MemberType> {
finalStringKEY='membertype';
finalMemberType defaultMemberType =MemberType.adult;
Map<String,MemberType> typeMap =const {
'adult':MemberType.adult,
'student':MemberType.student,
'unemployed':MemberType.unemployed,
'pensioner':MemberType.pensioner,
'child':MemberType.child,
'vip':MemberType.vip
};
@overrideboolcanDecode(value) => value isMemberType;
@overrideboolcanEncode(value) => value isMap&& value.containsKey(KEY);
dynamicencode(MemberType value) {
var type = value ==null? defaultMemberType : value;
for (var key in typeMap.keys) {
if (typeMap[key] == type) {
return {KEY: key};
}
}
thrownewArgumentError("unsupported type");
}
MemberTypedecode(dynamic value) => typeMap.containsKey(value[KEY]) ? typeMap[value[KEY]] : defaultMemberType;
}
main() {
var dynamo =newDynamo()
..addTransformer(newMemberTypeTransformer())
..registerType('member', Member, () =>newMember());
// dynamo.toJson(member);// dynamo.fromJson(member);
}
Transformer sample: Representation instead of whole mapped instance

E.g. if instances already known then only a representation (e.g. ID of an entity) can be serialized instead:

classMemberTransformerimplementsTypeTransformer<Member> {
staticconstStringKEY='memberId';
finalList<Member> members; // usually a repositoryMemberTransformer(this.members);
@overrideboolcanEncode(value) => value isMember;
@overrideencode(Member value) => {KEY: value.id};
@overrideboolcanDecode(value) => value isMap&& value.containsKey(KEY);
@overrideMemberdecode(value) => members.firstWhere((member) => member.id == value[KEY], orElse: () =>null);
}
// usually repositories for membersList<Member> members = [m1, m2, m3];
MemberTransformer memberTransformer =newMemberTransformer(members);
Dynamo dynamo =newDynamo()
..addTransformer(memberTransformer)
;
var output = dynamo.toJson(m2);

will produce:

 {"memberId":2}

datetime transformer

DateTime will be serialized automatically for fields but due to JSON restriction, can not be automatically detected if part of an untyped list oder map (only by guessing). If DateTime is used in untyped collections the bundled DateTimeTransformer can be used:

Dynamo dynamo =newDynamo()
..addTransformer(newDateTimeTransformer("_dt_"))
;

for values e.g. List values = [new DateTime.utc(2017,1,29), new DateTime.utc(2017,1,28)];

dynamo will produce

[
{"_dt_":"2017-01-29T00:00:00.000Z"},
{"_dt_":"2017-01-28T00:00:00.000Z"}
]

But now, also fields in registered type will use this transformer for DateTime fields:

{
"_isa_":"member",
"registered":{"_dt_":"2017-01-30T00:00:00.000Z"}
}

instead of (using internal datetime transformers for fields):

{
"_isa_":"member",
"registered":"2017-01-30T00:00:00.000Z"
}

generate pretty json output

classPrettyJsonCodecextendsJsonCodec {
JsonEncoderget encoder {
returnconstJsonEncoder.withIndent(' ');
}
}
newDynamo(codec:newPrettyJsonCodec()) ....

customize json keys for type and reference information

default keys:

  • typeKey: _isa_ (used to identify the type)
  • instanceIdKey: _id#_ (used to add a sequential number)
  • referenceKey: _ref_ (used to reference to a prior serialized instance)

Sample: serialize same instance (of type member) twice in a list:

[
{
"_isa_":"member",
"_id#_":1
},
{"_ref_":1}
]

To customize these key use following setters:

Dynamo dynamo =createCommonDynamo(JSON)
..typeKey =r"$typeof"
..instanceIdKey =r"$instance"
..referenceKey =r"$reference";

Same example will produce:

[
{
"$typeof":"member",
"$instance":1
},
{"$reference":1}
]

Example

See example of dynamo in Github Repo.

Not yet implemented

  • using different name for imported dynamo library (import as)

About

Dart JSON serialization for object graphs

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - gerald24/dynamo: Dart JSON serialization for object graphs · GitHub
Skip to content

Repository files navigation

dynamo

A JSON serialization for object graphs. This library will not generate a simple JSON but add some information for types and references. Thus this library supports circle references, inheritance and object graphs (reference aware).

Dynamo uses source_gen to generate code, and has no dependency to the 'dart:mirror' at all.

Dynamo is rewritten from scratch, but influenced from Dartson (dartson on github), with some some extensions to Dartson.

Alternatives

If you need just simple JSON serialization you might use JsonSerializable from source_gen instead, or Dartson. Latter uses code transformers.

Annotations

Serializable Objects must be annotated with @DynamoSerializable(), and also must use a generated mixin (Namepattern is _$classnameDynamoMixin) Fields with missing getter or setter will be ignored. Optional fields can be annotated with @DynamoEntry() in order to use a different json key, or be ignored for serialization.

@DynamoSerializable()
classMemberextendsObjectwith_$MemberDynamoMixin {
int id =0;
String firstName;
@DynamoEntry(name:'last_name')
String lastName;
DateTime registered;
@DynamoEntry(ignore:true)
bool ignoreMe;
Member();
Member.withIdAndName(this.id, this.firstName, this.lastName) {}
// will be ignored (no setter)boolget isNew => id <1;
}

Generate Mixins

Build steps are needed to setup. See the source_gen > Running Generators and example.

Serialization

The root object for serialization (toJson) or deserialization (fromJson) might be:

  • a list,
  • a map,
  • a simple type (bool, num, String),
  • or a registered type (annotated with DynamoSerializable and using a generated DynamoMixin).

The protocol for serialization is:

StringtoJson(dynamic value);
dynamicfromJson(String json, {InstanceFactoryfactory});

Usually fromJson will detect the target instance but optional a factory can be passed instead.

type registration

Since no mirroring system will be used, each type must be registered using registerType with an identifier, the type and a factory for new instances:

newDynamo()
..registerType('member', Member, () =>newMember())

dynamo configuration

Different dynamo configurations might be used (with the same serializable objects) to produce different JSON output.

var dynamo1 =newDynamo()
..addTransformer(newMemberTypeTransformer())
..registerType('member', Member, () =>newMember())
..registerType('tag', Tag, () =>newTag())
;
var dynamo2 =newDynamo()
..registerType('member', Member, () =>newMember())
..registerType('tag', Tag, () =>newTag())
..addTransformer(newMemberTransformer(allMembers))
;

transformers

A type transformer can be added to a dynamo (configuration) e.g for mapping enum values, or just a representation for an entity.

Transformer sample: Enum mapping
enumMemberType { adult, student, unemployed, pensioner, child, vip }
@DynamoSerializable()
classMemberextendsObjectwith_$MemberDynamoMixin {
MemberType type;
Member();
}
classMemberTypeTransformerextendsTypeTransformer<MemberType> {
finalStringKEY='membertype';
finalMemberType defaultMemberType =MemberType.adult;
Map<String,MemberType> typeMap =const {
'adult':MemberType.adult,
'student':MemberType.student,
'unemployed':MemberType.unemployed,
'pensioner':MemberType.pensioner,
'child':MemberType.child,
'vip':MemberType.vip
};
@overrideboolcanDecode(value) => value isMemberType;
@overrideboolcanEncode(value) => value isMap&& value.containsKey(KEY);
dynamicencode(MemberType value) {
var type = value ==null? defaultMemberType : value;
for (var key in typeMap.keys) {
if (typeMap[key] == type) {
return {KEY: key};
}
}
thrownewArgumentError("unsupported type");
}
MemberTypedecode(dynamic value) => typeMap.containsKey(value[KEY]) ? typeMap[value[KEY]] : defaultMemberType;
}
main() {
var dynamo =newDynamo()
..addTransformer(newMemberTypeTransformer())
..registerType('member', Member, () =>newMember());
// dynamo.toJson(member);// dynamo.fromJson(member);
}
Transformer sample: Representation instead of whole mapped instance

E.g. if instances already known then only a representation (e.g. ID of an entity) can be serialized instead:

classMemberTransformerimplementsTypeTransformer<Member> {
staticconstStringKEY='memberId';
finalList<Member> members; // usually a repositoryMemberTransformer(this.members);
@overrideboolcanEncode(value) => value isMember;
@overrideencode(Member value) => {KEY: value.id};
@overrideboolcanDecode(value) => value isMap&& value.containsKey(KEY);
@overrideMemberdecode(value) => members.firstWhere((member) => member.id == value[KEY], orElse: () =>null);
}
// usually repositories for membersList<Member> members = [m1, m2, m3];
MemberTransformer memberTransformer =newMemberTransformer(members);
Dynamo dynamo =newDynamo()
..addTransformer(memberTransformer)
;
var output = dynamo.toJson(m2);

will produce:

 {"memberId":2}

datetime transformer

DateTime will be serialized automatically for fields but due to JSON restriction, can not be automatically detected if part of an untyped list oder map (only by guessing). If DateTime is used in untyped collections the bundled DateTimeTransformer can be used:

Dynamo dynamo =newDynamo()
..addTransformer(newDateTimeTransformer("_dt_"))
;

for values e.g. List values = [new DateTime.utc(2017,1,29), new DateTime.utc(2017,1,28)];

dynamo will produce

[
{"_dt_":"2017-01-29T00:00:00.000Z"},
{"_dt_":"2017-01-28T00:00:00.000Z"}
]

But now, also fields in registered type will use this transformer for DateTime fields:

{
"_isa_":"member",
"registered":{"_dt_":"2017-01-30T00:00:00.000Z"}
}

instead of (using internal datetime transformers for fields):

{
"_isa_":"member",
"registered":"2017-01-30T00:00:00.000Z"
}

generate pretty json output

classPrettyJsonCodecextendsJsonCodec {
JsonEncoderget encoder {
returnconstJsonEncoder.withIndent(' ');
}
}
newDynamo(codec:newPrettyJsonCodec()) ....

customize json keys for type and reference information

default keys:

  • typeKey: _isa_ (used to identify the type)
  • instanceIdKey: _id#_ (used to add a sequential number)
  • referenceKey: _ref_ (used to reference to a prior serialized instance)

Sample: serialize same instance (of type member) twice in a list:

[
{
"_isa_":"member",
"_id#_":1
},
{"_ref_":1}
]

To customize these key use following setters:

Dynamo dynamo =createCommonDynamo(JSON)
..typeKey =r"$typeof"
..instanceIdKey =r"$instance"
..referenceKey =r"$reference";

Same example will produce:

[
{
"$typeof":"member",
"$instance":1
},
{"$reference":1}
]

Example

See example of dynamo in Github Repo.

Not yet implemented

  • using different name for imported dynamo library (import as)

About

Dart JSON serialization for object graphs

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' GitHub - gerald24/dynamo: Dart JSON serialization for object graphs · GitHub
Skip to content

Repository files navigation

dynamo

A JSON serialization for object graphs. This library will not generate a simple JSON but add some information for types and references. Thus this library supports circle references, inheritance and object graphs (reference aware).

Dynamo uses source_gen to generate code, and has no dependency to the 'dart:mirror' at all.

Dynamo is rewritten from scratch, but influenced from Dartson (dartson on github), with some some extensions to Dartson.

Alternatives

If you need just simple JSON serialization you might use JsonSerializable from source_gen instead, or Dartson. Latter uses code transformers.

Annotations

Serializable Objects must be annotated with @DynamoSerializable(), and also must use a generated mixin (Namepattern is _$classnameDynamoMixin) Fields with missing getter or setter will be ignored. Optional fields can be annotated with @DynamoEntry() in order to use a different json key, or be ignored for serialization.

@DynamoSerializable()
classMemberextendsObjectwith_$MemberDynamoMixin {
int id =0;
String firstName;
@DynamoEntry(name:'last_name')
String lastName;
DateTime registered;
@DynamoEntry(ignore:true)
bool ignoreMe;
Member();
Member.withIdAndName(this.id, this.firstName, this.lastName) {}
// will be ignored (no setter)boolget isNew => id <1;
}

Generate Mixins

Build steps are needed to setup. See the source_gen > Running Generators and example.

Serialization

The root object for serialization (toJson) or deserialization (fromJson) might be:

  • a list,
  • a map,
  • a simple type (bool, num, String),
  • or a registered type (annotated with DynamoSerializable and using a generated DynamoMixin).

The protocol for serialization is:

StringtoJson(dynamic value);
dynamicfromJson(String json, {InstanceFactoryfactory});

Usually fromJson will detect the target instance but optional a factory can be passed instead.

type registration

Since no mirroring system will be used, each type must be registered using registerType with an identifier, the type and a factory for new instances:

newDynamo()
..registerType('member', Member, () =>newMember())

dynamo configuration

Different dynamo configurations might be used (with the same serializable objects) to produce different JSON output.

var dynamo1 =newDynamo()
..addTransformer(newMemberTypeTransformer())
..registerType('member', Member, () =>newMember())
..registerType('tag', Tag, () =>newTag())
;
var dynamo2 =newDynamo()
..registerType('member', Member, () =>newMember())
..registerType('tag', Tag, () =>newTag())
..addTransformer(newMemberTransformer(allMembers))
;

transformers

A type transformer can be added to a dynamo (configuration) e.g for mapping enum values, or just a representation for an entity.

Transformer sample: Enum mapping
enumMemberType { adult, student, unemployed, pensioner, child, vip }
@DynamoSerializable()
classMemberextendsObjectwith_$MemberDynamoMixin {
MemberType type;
Member();
}
classMemberTypeTransformerextendsTypeTransformer<MemberType> {
finalStringKEY='membertype';
finalMemberType defaultMemberType =MemberType.adult;
Map<String,MemberType> typeMap =const {
'adult':MemberType.adult,
'student':MemberType.student,
'unemployed':MemberType.unemployed,
'pensioner':MemberType.pensioner,
'child':MemberType.child,
'vip':MemberType.vip
};
@overrideboolcanDecode(value) => value isMemberType;
@overrideboolcanEncode(value) => value isMap&& value.containsKey(KEY);
dynamicencode(MemberType value) {
var type = value ==null? defaultMemberType : value;
for (var key in typeMap.keys) {
if (typeMap[key] == type) {
return {KEY: key};
}
}
thrownewArgumentError("unsupported type");
}
MemberTypedecode(dynamic value) => typeMap.containsKey(value[KEY]) ? typeMap[value[KEY]] : defaultMemberType;
}
main() {
var dynamo =newDynamo()
..addTransformer(newMemberTypeTransformer())
..registerType('member', Member, () =>newMember());
// dynamo.toJson(member);// dynamo.fromJson(member);
}
Transformer sample: Representation instead of whole mapped instance

E.g. if instances already known then only a representation (e.g. ID of an entity) can be serialized instead:

classMemberTransformerimplementsTypeTransformer<Member> {
staticconstStringKEY='memberId';
finalList<Member> members; // usually a repositoryMemberTransformer(this.members);
@overrideboolcanEncode(value) => value isMember;
@overrideencode(Member value) => {KEY: value.id};
@overrideboolcanDecode(value) => value isMap&& value.containsKey(KEY);
@overrideMemberdecode(value) => members.firstWhere((member) => member.id == value[KEY], orElse: () =>null);
}
// usually repositories for membersList<Member> members = [m1, m2, m3];
MemberTransformer memberTransformer =newMemberTransformer(members);
Dynamo dynamo =newDynamo()
..addTransformer(memberTransformer)
;
var output = dynamo.toJson(m2);

will produce:

 {"memberId":2}

datetime transformer

DateTime will be serialized automatically for fields but due to JSON restriction, can not be automatically detected if part of an untyped list oder map (only by guessing). If DateTime is used in untyped collections the bundled DateTimeTransformer can be used:

Dynamo dynamo =newDynamo()
..addTransformer(newDateTimeTransformer("_dt_"))
;

for values e.g. List values = [new DateTime.utc(2017,1,29), new DateTime.utc(2017,1,28)];

dynamo will produce

[
{"_dt_":"2017-01-29T00:00:00.000Z"},
{"_dt_":"2017-01-28T00:00:00.000Z"}
]

But now, also fields in registered type will use this transformer for DateTime fields:

{
"_isa_":"member",
"registered":{"_dt_":"2017-01-30T00:00:00.000Z"}
}

instead of (using internal datetime transformers for fields):

{
"_isa_":"member",
"registered":"2017-01-30T00:00:00.000Z"
}

generate pretty json output

classPrettyJsonCodecextendsJsonCodec {
JsonEncoderget encoder {
returnconstJsonEncoder.withIndent(' ');
}
}
newDynamo(codec:newPrettyJsonCodec()) ....

customize json keys for type and reference information

default keys:

  • typeKey: _isa_ (used to identify the type)
  • instanceIdKey: _id#_ (used to add a sequential number)
  • referenceKey: _ref_ (used to reference to a prior serialized instance)

Sample: serialize same instance (of type member) twice in a list:

[
{
"_isa_":"member",
"_id#_":1
},
{"_ref_":1}
]

To customize these key use following setters:

Dynamo dynamo =createCommonDynamo(JSON)
..typeKey =r"$typeof"
..instanceIdKey =r"$instance"
..referenceKey =r"$reference";

Same example will produce:

[
{
"$typeof":"member",
"$instance":1
},
{"$reference":1}
]

Example

See example of dynamo in Github Repo.

Not yet implemented

  • using different name for imported dynamo library (import as)

About

Dart JSON serialization for object graphs

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - gerald24/dynamo: Dart JSON serialization for object graphs · GitHub
Skip to content

Repository files navigation

dynamo

A JSON serialization for object graphs. This library will not generate a simple JSON but add some information for types and references. Thus this library supports circle references, inheritance and object graphs (reference aware).

Dynamo uses source_gen to generate code, and has no dependency to the 'dart:mirror' at all.

Dynamo is rewritten from scratch, but influenced from Dartson (dartson on github), with some some extensions to Dartson.

Alternatives

If you need just simple JSON serialization you might use JsonSerializable from source_gen instead, or Dartson. Latter uses code transformers.

Annotations

Serializable Objects must be annotated with @DynamoSerializable(), and also must use a generated mixin (Namepattern is _$classnameDynamoMixin) Fields with missing getter or setter will be ignored. Optional fields can be annotated with @DynamoEntry() in order to use a different json key, or be ignored for serialization.

@DynamoSerializable()
classMemberextendsObjectwith_$MemberDynamoMixin {
int id =0;
String firstName;
@DynamoEntry(name:'last_name')
String lastName;
DateTime registered;
@DynamoEntry(ignore:true)
bool ignoreMe;
Member();
Member.withIdAndName(this.id, this.firstName, this.lastName) {}
// will be ignored (no setter)boolget isNew => id <1;
}

Generate Mixins

Build steps are needed to setup. See the source_gen > Running Generators and example.

Serialization

The root object for serialization (toJson) or deserialization (fromJson) might be:

  • a list,
  • a map,
  • a simple type (bool, num, String),
  • or a registered type (annotated with DynamoSerializable and using a generated DynamoMixin).

The protocol for serialization is:

StringtoJson(dynamic value);
dynamicfromJson(String json, {InstanceFactoryfactory});

Usually fromJson will detect the target instance but optional a factory can be passed instead.

type registration

Since no mirroring system will be used, each type must be registered using registerType with an identifier, the type and a factory for new instances:

newDynamo()
..registerType('member', Member, () =>newMember())

dynamo configuration

Different dynamo configurations might be used (with the same serializable objects) to produce different JSON output.

var dynamo1 =newDynamo()
..addTransformer(newMemberTypeTransformer())
..registerType('member', Member, () =>newMember())
..registerType('tag', Tag, () =>newTag())
;
var dynamo2 =newDynamo()
..registerType('member', Member, () =>newMember())
..registerType('tag', Tag, () =>newTag())
..addTransformer(newMemberTransformer(allMembers))
;

transformers

A type transformer can be added to a dynamo (configuration) e.g for mapping enum values, or just a representation for an entity.

Transformer sample: Enum mapping
enumMemberType { adult, student, unemployed, pensioner, child, vip }
@DynamoSerializable()
classMemberextendsObjectwith_$MemberDynamoMixin {
MemberType type;
Member();
}
classMemberTypeTransformerextendsTypeTransformer<MemberType> {
finalStringKEY='membertype';
finalMemberType defaultMemberType =MemberType.adult;
Map<String,MemberType> typeMap =const {
'adult':MemberType.adult,
'student':MemberType.student,
'unemployed':MemberType.unemployed,
'pensioner':MemberType.pensioner,
'child':MemberType.child,
'vip':MemberType.vip
};
@overrideboolcanDecode(value) => value isMemberType;
@overrideboolcanEncode(value) => value isMap&& value.containsKey(KEY);
dynamicencode(MemberType value) {
var type = value ==null? defaultMemberType : value;
for (var key in typeMap.keys) {
if (typeMap[key] == type) {
return {KEY: key};
}
}
thrownewArgumentError("unsupported type");
}
MemberTypedecode(dynamic value) => typeMap.containsKey(value[KEY]) ? typeMap[value[KEY]] : defaultMemberType;
}
main() {
var dynamo =newDynamo()
..addTransformer(newMemberTypeTransformer())
..registerType('member', Member, () =>newMember());
// dynamo.toJson(member);// dynamo.fromJson(member);
}
Transformer sample: Representation instead of whole mapped instance

E.g. if instances already known then only a representation (e.g. ID of an entity) can be serialized instead:

classMemberTransformerimplementsTypeTransformer<Member> {
staticconstStringKEY='memberId';
finalList<Member> members; // usually a repositoryMemberTransformer(this.members);
@overrideboolcanEncode(value) => value isMember;
@overrideencode(Member value) => {KEY: value.id};
@overrideboolcanDecode(value) => value isMap&& value.containsKey(KEY);
@overrideMemberdecode(value) => members.firstWhere((member) => member.id == value[KEY], orElse: () =>null);
}
// usually repositories for membersList<Member> members = [m1, m2, m3];
MemberTransformer memberTransformer =newMemberTransformer(members);
Dynamo dynamo =newDynamo()
..addTransformer(memberTransformer)
;
var output = dynamo.toJson(m2);

will produce:

 {"memberId":2}

datetime transformer

DateTime will be serialized automatically for fields but due to JSON restriction, can not be automatically detected if part of an untyped list oder map (only by guessing). If DateTime is used in untyped collections the bundled DateTimeTransformer can be used:

Dynamo dynamo =newDynamo()
..addTransformer(newDateTimeTransformer("_dt_"))
;

for values e.g. List values = [new DateTime.utc(2017,1,29), new DateTime.utc(2017,1,28)];

dynamo will produce

[
{"_dt_":"2017-01-29T00:00:00.000Z"},
{"_dt_":"2017-01-28T00:00:00.000Z"}
]

But now, also fields in registered type will use this transformer for DateTime fields:

{
"_isa_":"member",
"registered":{"_dt_":"2017-01-30T00:00:00.000Z"}
}

instead of (using internal datetime transformers for fields):

{
"_isa_":"member",
"registered":"2017-01-30T00:00:00.000Z"
}

generate pretty json output

classPrettyJsonCodecextendsJsonCodec {
JsonEncoderget encoder {
returnconstJsonEncoder.withIndent(' ');
}
}
newDynamo(codec:newPrettyJsonCodec()) ....

customize json keys for type and reference information

default keys:

  • typeKey: _isa_ (used to identify the type)
  • instanceIdKey: _id#_ (used to add a sequential number)
  • referenceKey: _ref_ (used to reference to a prior serialized instance)

Sample: serialize same instance (of type member) twice in a list:

[
{
"_isa_":"member",
"_id#_":1
},
{"_ref_":1}
]

To customize these key use following setters:

Dynamo dynamo =createCommonDynamo(JSON)
..typeKey =r"$typeof"
..instanceIdKey =r"$instance"
..referenceKey =r"$reference";

Same example will produce:

[
{
"$typeof":"member",
"$instance":1
},
{"$reference":1}
]

Example

See example of dynamo in Github Repo.

Not yet implemented

  • using different name for imported dynamo library (import as)

About

Dart JSON serialization for object graphs

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); GitHub - gerald24/dynamo: Dart JSON serialization for object graphs · GitHub
Skip to content

Repository files navigation

dynamo

A JSON serialization for object graphs. This library will not generate a simple JSON but add some information for types and references. Thus this library supports circle references, inheritance and object graphs (reference aware).

Dynamo uses source_gen to generate code, and has no dependency to the 'dart:mirror' at all.

Dynamo is rewritten from scratch, but influenced from Dartson (dartson on github), with some some extensions to Dartson.

Alternatives

If you need just simple JSON serialization you might use JsonSerializable from source_gen instead, or Dartson. Latter uses code transformers.

Annotations

Serializable Objects must be annotated with @DynamoSerializable(), and also must use a generated mixin (Namepattern is _$classnameDynamoMixin) Fields with missing getter or setter will be ignored. Optional fields can be annotated with @DynamoEntry() in order to use a different json key, or be ignored for serialization.

@DynamoSerializable()
classMemberextendsObjectwith_$MemberDynamoMixin {
int id =0;
String firstName;
@DynamoEntry(name:'last_name')
String lastName;
DateTime registered;
@DynamoEntry(ignore:true)
bool ignoreMe;
Member();
Member.withIdAndName(this.id, this.firstName, this.lastName) {}
// will be ignored (no setter)boolget isNew => id <1;
}

Generate Mixins

Build steps are needed to setup. See the source_gen > Running Generators and example.

Serialization

The root object for serialization (toJson) or deserialization (fromJson) might be:

  • a list,
  • a map,
  • a simple type (bool, num, String),
  • or a registered type (annotated with DynamoSerializable and using a generated DynamoMixin).

The protocol for serialization is:

StringtoJson(dynamic value);
dynamicfromJson(String json, {InstanceFactoryfactory});

Usually fromJson will detect the target instance but optional a factory can be passed instead.

type registration

Since no mirroring system will be used, each type must be registered using registerType with an identifier, the type and a factory for new instances:

newDynamo()
..registerType('member', Member, () =>newMember())

dynamo configuration

Different dynamo configurations might be used (with the same serializable objects) to produce different JSON output.

var dynamo1 =newDynamo()
..addTransformer(newMemberTypeTransformer())
..registerType('member', Member, () =>newMember())
..registerType('tag', Tag, () =>newTag())
;
var dynamo2 =newDynamo()
..registerType('member', Member, () =>newMember())
..registerType('tag', Tag, () =>newTag())
..addTransformer(newMemberTransformer(allMembers))
;

transformers

A type transformer can be added to a dynamo (configuration) e.g for mapping enum values, or just a representation for an entity.

Transformer sample: Enum mapping
enumMemberType { adult, student, unemployed, pensioner, child, vip }
@DynamoSerializable()
classMemberextendsObjectwith_$MemberDynamoMixin {
MemberType type;
Member();
}
classMemberTypeTransformerextendsTypeTransformer<MemberType> {
finalStringKEY='membertype';
finalMemberType defaultMemberType =MemberType.adult;
Map<String,MemberType> typeMap =const {
'adult':MemberType.adult,
'student':MemberType.student,
'unemployed':MemberType.unemployed,
'pensioner':MemberType.pensioner,
'child':MemberType.child,
'vip':MemberType.vip
};
@overrideboolcanDecode(value) => value isMemberType;
@overrideboolcanEncode(value) => value isMap&& value.containsKey(KEY);
dynamicencode(MemberType value) {
var type = value ==null? defaultMemberType : value;
for (var key in typeMap.keys) {
if (typeMap[key] == type) {
return {KEY: key};
}
}
thrownewArgumentError("unsupported type");
}
MemberTypedecode(dynamic value) => typeMap.containsKey(value[KEY]) ? typeMap[value[KEY]] : defaultMemberType;
}
main() {
var dynamo =newDynamo()
..addTransformer(newMemberTypeTransformer())
..registerType('member', Member, () =>newMember());
// dynamo.toJson(member);// dynamo.fromJson(member);
}
Transformer sample: Representation instead of whole mapped instance

E.g. if instances already known then only a representation (e.g. ID of an entity) can be serialized instead:

classMemberTransformerimplementsTypeTransformer<Member> {
staticconstStringKEY='memberId';
finalList<Member> members; // usually a repositoryMemberTransformer(this.members);
@overrideboolcanEncode(value) => value isMember;
@overrideencode(Member value) => {KEY: value.id};
@overrideboolcanDecode(value) => value isMap&& value.containsKey(KEY);
@overrideMemberdecode(value) => members.firstWhere((member) => member.id == value[KEY], orElse: () =>null);
}
// usually repositories for membersList<Member> members = [m1, m2, m3];
MemberTransformer memberTransformer =newMemberTransformer(members);
Dynamo dynamo =newDynamo()
..addTransformer(memberTransformer)
;
var output = dynamo.toJson(m2);

will produce:

 {"memberId":2}

datetime transformer

DateTime will be serialized automatically for fields but due to JSON restriction, can not be automatically detected if part of an untyped list oder map (only by guessing). If DateTime is used in untyped collections the bundled DateTimeTransformer can be used:

Dynamo dynamo =newDynamo()
..addTransformer(newDateTimeTransformer("_dt_"))
;

for values e.g. List values = [new DateTime.utc(2017,1,29), new DateTime.utc(2017,1,28)];

dynamo will produce

[
{"_dt_":"2017-01-29T00:00:00.000Z"},
{"_dt_":"2017-01-28T00:00:00.000Z"}
]

But now, also fields in registered type will use this transformer for DateTime fields:

{
"_isa_":"member",
"registered":{"_dt_":"2017-01-30T00:00:00.000Z"}
}

instead of (using internal datetime transformers for fields):

{
"_isa_":"member",
"registered":"2017-01-30T00:00:00.000Z"
}

generate pretty json output

classPrettyJsonCodecextendsJsonCodec {
JsonEncoderget encoder {
returnconstJsonEncoder.withIndent(' ');
}
}
newDynamo(codec:newPrettyJsonCodec()) ....

customize json keys for type and reference information

default keys:

  • typeKey: _isa_ (used to identify the type)
  • instanceIdKey: _id#_ (used to add a sequential number)
  • referenceKey: _ref_ (used to reference to a prior serialized instance)

Sample: serialize same instance (of type member) twice in a list:

[
{
"_isa_":"member",
"_id#_":1
},
{"_ref_":1}
]

To customize these key use following setters:

Dynamo dynamo =createCommonDynamo(JSON)
..typeKey =r"$typeof"
..instanceIdKey =r"$instance"
..referenceKey =r"$reference";

Same example will produce:

[
{
"$typeof":"member",
"$instance":1
},
{"$reference":1}
]

Example

See example of dynamo in Github Repo.

Not yet implemented

  • using different name for imported dynamo library (import as)

About

Dart JSON serialization for object graphs

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages