include annotations
This commit is contained in:
parent
a30b99a821
commit
4dc0153cbf
10 changed files with 205 additions and 62 deletions
33
README.md
33
README.md
|
@ -12,6 +12,7 @@ the time you spend writing boilerplate serialization code for your models.
|
||||||
- [Field Aliases](#aliases)
|
- [Field Aliases](#aliases)
|
||||||
- [Excluding Keys](#excluding-keys)
|
- [Excluding Keys](#excluding-keys)
|
||||||
- [Required Fields](#required-fields)
|
- [Required Fields](#required-fields)
|
||||||
|
- [Adding Annotations to Generated Classes](#adding-annotations-to-generated-classes)
|
||||||
- [Serialization](#serializaition)
|
- [Serialization](#serializaition)
|
||||||
- [Nesting](#nesting)
|
- [Nesting](#nesting)
|
||||||
- [ID and Date Fields](#id-and-dates)
|
- [ID and Date Fields](#id-and-dates)
|
||||||
|
@ -67,7 +68,7 @@ part 'book.g.dart';
|
||||||
abstract class _Book extends Model {
|
abstract class _Book extends Model {
|
||||||
String get author;
|
String get author;
|
||||||
|
|
||||||
@DefaultValue('[Untitled]')
|
@SerializableField(defaultValue: '[Untitled]')
|
||||||
String get title;
|
String get title;
|
||||||
|
|
||||||
String get description;
|
String get description;
|
||||||
|
@ -155,7 +156,7 @@ 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
|
tend to be snake_cased. This is not a problem, because we can define an alias
|
||||||
for a field.
|
for a field.
|
||||||
|
|
||||||
By default `angel_serialize` will transform keys into snake case. Use `Alias` to
|
By default `angel_serialize` will transform keys into snake case. Use `alias` to
|
||||||
provide a custom name, or pass `autoSnakeCaseNames`: `false` to the builder;
|
provide a custom name, or pass `autoSnakeCaseNames`: `false` to the builder;
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
|
@ -169,7 +170,7 @@ abstract class _Spy extends Model {
|
||||||
/// Hooray!
|
/// Hooray!
|
||||||
String agencyId;
|
String agencyId;
|
||||||
|
|
||||||
@Alias('foo')
|
@SerializableField(alias: 'foo')
|
||||||
String someOtherField;
|
String someOtherField;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -192,7 +193,7 @@ To accomplish this, simply annotate them with `@exclude`:
|
||||||
@serializable
|
@serializable
|
||||||
abstract class _Whisper extends Model {
|
abstract class _Whisper extends Model {
|
||||||
/// Will never be serialized to JSON
|
/// Will never be serialized to JSON
|
||||||
@exclude
|
@SerializableField(exclude: true)
|
||||||
String secret;
|
String secret;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -209,23 +210,22 @@ abstract class _Whisper extends Model {
|
||||||
/// Will never be serialized to JSON
|
/// Will never be serialized to JSON
|
||||||
///
|
///
|
||||||
/// ... But it can be deserialized
|
/// ... But it can be deserialized
|
||||||
@Exclude(canDeserialize: true)
|
@SerializableField(exclude: true, canDeserialize: true)
|
||||||
String secret;
|
String secret;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Required Fields
|
## Required Fields
|
||||||
|
|
||||||
It is easy to mark a field as required; just use the
|
It is easy to mark a field as required:
|
||||||
`@required` annotation from `package:meta`:
|
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
@serializable
|
@serializable
|
||||||
abstract class _Foo extends Model {
|
abstract class _Foo extends Model {
|
||||||
@required
|
@SerializableField(isNullable: false)
|
||||||
int myRequiredInt;
|
int myRequiredInt;
|
||||||
|
|
||||||
@Required('Custom message')
|
@SerializableField(isNullable: false, errorMessage: 'Custom message')
|
||||||
int myOtherRequiredInt;
|
int myOtherRequiredInt;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -234,6 +234,19 @@ The given field will be marked as `@required` in the
|
||||||
generated constructor, and serializers will check for its
|
generated constructor, and serializers will check for its
|
||||||
presence, throwing a `FormatException` if it is missing.
|
presence, throwing a `FormatException` if it is missing.
|
||||||
|
|
||||||
|
## Adding Annotations to Generated Classes
|
||||||
|
There are times when you need the generated class to have annotations affixed to it:
|
||||||
|
|
||||||
|
```dart
|
||||||
|
@Serializable(
|
||||||
|
includeAnnotations: [
|
||||||
|
Deprecated('blah blah blah'),
|
||||||
|
pragma('something...'),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
abstract class _Foo extends Model {}
|
||||||
|
```
|
||||||
|
|
||||||
# Nesting
|
# Nesting
|
||||||
|
|
||||||
`angel_serialize` also supports a few types of nesting of `@serializable` classes:
|
`angel_serialize` also supports a few types of nesting of `@serializable` classes:
|
||||||
|
@ -327,7 +340,7 @@ The following:
|
||||||
```dart
|
```dart
|
||||||
@serializable
|
@serializable
|
||||||
abstract class _Bookmark extends _BookmarkBase {
|
abstract class _Bookmark extends _BookmarkBase {
|
||||||
@exclude
|
@SerializableField(exclude: true)
|
||||||
final Book book;
|
final Book book;
|
||||||
|
|
||||||
int get page;
|
int get page;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
export 'package:quiver_hashcode/hashcode.dart' show hashObjects;
|
export 'package:quiver_hashcode/hashcode.dart' show hashObjects;
|
||||||
|
|
||||||
/// Excludes a field from being excluded.
|
/// Excludes a field from being excluded.
|
||||||
|
@deprecated
|
||||||
class Exclude {
|
class Exclude {
|
||||||
final bool canSerialize;
|
final bool canSerialize;
|
||||||
|
|
||||||
|
@ -9,6 +10,8 @@ class Exclude {
|
||||||
const Exclude({this.canDeserialize: false, this.canSerialize: false});
|
const Exclude({this.canDeserialize: false, this.canSerialize: false});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@deprecated
|
||||||
|
// ignore: deprecated_member_use
|
||||||
const Exclude exclude = const Exclude();
|
const Exclude exclude = const Exclude();
|
||||||
|
|
||||||
@deprecated
|
@deprecated
|
||||||
|
@ -34,15 +37,31 @@ class SerializableField {
|
||||||
/// A custom serializer for this field.
|
/// A custom serializer for this field.
|
||||||
final Symbol deserializer;
|
final Symbol deserializer;
|
||||||
|
|
||||||
/// A list of constant members to affix to the generated class.
|
/// An error message to be printed when the provided value is invalid.
|
||||||
final List includeAnnotations;
|
final String errorMessage;
|
||||||
|
|
||||||
SerializableField(
|
/// Whether this field can be set to `null`.
|
||||||
|
final bool isNullable;
|
||||||
|
|
||||||
|
/// Whether to exclude this field from serialization. Defaults to `false`.
|
||||||
|
final bool exclude;
|
||||||
|
|
||||||
|
/// Whether this field can be serialized, if [exclude] is `true`. Defaults to `false`.
|
||||||
|
final bool canDeserialize;
|
||||||
|
|
||||||
|
/// Whether this field can be serialized, if [exclude] is `true`. Defaults to `false`.
|
||||||
|
final bool canSerialize;
|
||||||
|
|
||||||
|
const SerializableField(
|
||||||
{this.alias,
|
{this.alias,
|
||||||
this.defaultValue,
|
this.defaultValue,
|
||||||
this.serializer,
|
this.serializer,
|
||||||
this.deserializer,
|
this.deserializer,
|
||||||
this.includeAnnotations: const []});
|
this.errorMessage,
|
||||||
|
this.isNullable: true,
|
||||||
|
this.exclude: false,
|
||||||
|
this.canDeserialize: false,
|
||||||
|
this.canSerialize: false});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Marks a class as eligible for serialization.
|
/// Marks a class as eligible for serialization.
|
||||||
|
@ -50,7 +69,8 @@ class Serializable {
|
||||||
const Serializable(
|
const Serializable(
|
||||||
{this.serializers: const [Serializers.map, Serializers.json],
|
{this.serializers: const [Serializers.map, Serializers.json],
|
||||||
this.autoSnakeCaseNames: true,
|
this.autoSnakeCaseNames: true,
|
||||||
this.autoIdAndDateFields: true});
|
this.autoIdAndDateFields: true,
|
||||||
|
this.includeAnnotations: const []});
|
||||||
|
|
||||||
/// A list of enabled serialization modes.
|
/// A list of enabled serialization modes.
|
||||||
///
|
///
|
||||||
|
@ -62,6 +82,9 @@ class Serializable {
|
||||||
|
|
||||||
/// Overrides the setting in `JsonModelGenerator`.
|
/// Overrides the setting in `JsonModelGenerator`.
|
||||||
final bool autoIdAndDateFields;
|
final bool autoIdAndDateFields;
|
||||||
|
|
||||||
|
/// A list of constant members to affix to the generated class.
|
||||||
|
final List includeAnnotations;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Serializable serializable = const Serializable();
|
const Serializable serializable = const Serializable();
|
||||||
|
|
|
@ -48,6 +48,30 @@ TypeReference convertTypeReference(DartType t) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Expression convertObject(DartObject o) {
|
||||||
|
if (o.isNull) return literalNull;
|
||||||
|
if (o.toBoolValue() != null) return literalBool(o.toBoolValue());
|
||||||
|
if (o.toIntValue() != null) return literalNum(o.toIntValue());
|
||||||
|
if (o.toDoubleValue() != null) return literalNum(o.toDoubleValue());
|
||||||
|
if (o.toSymbolValue() != null)
|
||||||
|
return CodeExpression(Code('#' + o.toSymbolValue()));
|
||||||
|
if (o.toStringValue() != null) return literalString(o.toStringValue());
|
||||||
|
if (o.toTypeValue() != null) return convertTypeReference(o.toTypeValue());
|
||||||
|
if (o.toListValue() != null)
|
||||||
|
return literalList(o.toListValue().map(convertObject));
|
||||||
|
if (o.toMapValue() != null) {
|
||||||
|
return literalMap(o
|
||||||
|
.toMapValue()
|
||||||
|
.map((k, v) => MapEntry(convertObject(k), convertObject(v))));
|
||||||
|
}
|
||||||
|
|
||||||
|
var rev = ConstantReader(o).revive();
|
||||||
|
Expression target = convertTypeReference(o.type);
|
||||||
|
target = rev.accessor.isEmpty ? target : target.property(rev.accessor);
|
||||||
|
return target.call(rev.positionalArguments.map(convertObject),
|
||||||
|
rev.namedArguments.map((k, v) => MapEntry(k, convertObject(v))));
|
||||||
|
}
|
||||||
|
|
||||||
String dartObjectToString(DartObject v) {
|
String dartObjectToString(DartObject v) {
|
||||||
if (v.isNull) return 'null';
|
if (v.isNull) return 'null';
|
||||||
if (v.toBoolValue() != null) return v.toBoolValue().toString();
|
if (v.toBoolValue() != null) return v.toBoolValue().toString();
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'package:analyzer/dart/constant/value.dart';
|
||||||
import 'package:analyzer/dart/element/element.dart';
|
import 'package:analyzer/dart/element/element.dart';
|
||||||
import 'package:analyzer/dart/element/type.dart';
|
import 'package:analyzer/dart/element/type.dart';
|
||||||
import 'package:analyzer/src/dart/element/element.dart';
|
import 'package:analyzer/src/dart/element/element.dart';
|
||||||
|
@ -10,12 +11,17 @@ import 'package:recase/recase.dart';
|
||||||
import 'package:source_gen/source_gen.dart';
|
import 'package:source_gen/source_gen.dart';
|
||||||
import 'context.dart';
|
import 'context.dart';
|
||||||
|
|
||||||
|
// ignore: deprecated_member_use
|
||||||
const TypeChecker aliasTypeChecker = const TypeChecker.fromRuntime(Alias);
|
const TypeChecker aliasTypeChecker = const TypeChecker.fromRuntime(Alias);
|
||||||
|
|
||||||
const TypeChecker dateTimeTypeChecker = const TypeChecker.fromRuntime(DateTime);
|
const TypeChecker dateTimeTypeChecker = const TypeChecker.fromRuntime(DateTime);
|
||||||
|
|
||||||
|
// ignore: deprecated_member_use
|
||||||
const TypeChecker excludeTypeChecker = const TypeChecker.fromRuntime(Exclude);
|
const TypeChecker excludeTypeChecker = const TypeChecker.fromRuntime(Exclude);
|
||||||
|
|
||||||
|
const TypeChecker serializableFieldTypeChecker =
|
||||||
|
const TypeChecker.fromRuntime(SerializableField);
|
||||||
|
|
||||||
const TypeChecker serializableTypeChecker =
|
const TypeChecker serializableTypeChecker =
|
||||||
const TypeChecker.fromRuntime(Serializable);
|
const TypeChecker.fromRuntime(Serializable);
|
||||||
|
|
||||||
|
@ -37,11 +43,16 @@ Future<BuildContext> buildContext(
|
||||||
autoSnakeCaseNames =
|
autoSnakeCaseNames =
|
||||||
annotation.peek('autoSnakeCaseNames')?.boolValue ?? autoSnakeCaseNames;
|
annotation.peek('autoSnakeCaseNames')?.boolValue ?? autoSnakeCaseNames;
|
||||||
|
|
||||||
var ctx = new BuildContext(annotation, clazz,
|
var ctx = new BuildContext(
|
||||||
originalClassName: clazz.name,
|
annotation,
|
||||||
sourceFilename: p.basename(buildStep.inputId.path),
|
clazz,
|
||||||
autoIdAndDateFields: autoIdAndDateFields,
|
originalClassName: clazz.name,
|
||||||
autoSnakeCaseNames: autoSnakeCaseNames);
|
sourceFilename: p.basename(buildStep.inputId.path),
|
||||||
|
autoIdAndDateFields: autoIdAndDateFields,
|
||||||
|
autoSnakeCaseNames: autoSnakeCaseNames,
|
||||||
|
includeAnnotations:
|
||||||
|
annotation.peek('includeAnnotations')?.listValue ?? <DartObject>[],
|
||||||
|
);
|
||||||
var lib = await resolver.libraryFor(buildStep.inputId);
|
var lib = await resolver.libraryFor(buildStep.inputId);
|
||||||
List<String> fieldNames = [];
|
List<String> fieldNames = [];
|
||||||
|
|
||||||
|
@ -55,49 +66,100 @@ Future<BuildContext> buildContext(
|
||||||
(field.setter != null || field.getter.isAbstract)) {
|
(field.setter != null || field.getter.isAbstract)) {
|
||||||
var el = field.setter == null ? field.getter : field;
|
var el = field.setter == null ? field.getter : field;
|
||||||
fieldNames.add(field.name);
|
fieldNames.add(field.name);
|
||||||
// Skip if annotated with @exclude
|
|
||||||
var excludeAnnotation = excludeTypeChecker.firstAnnotationOf(el);
|
|
||||||
|
|
||||||
if (excludeAnnotation != null) {
|
// Check for @SerializableField
|
||||||
var cr = new ConstantReader(excludeAnnotation);
|
var fieldAnn = serializableFieldTypeChecker.firstAnnotationOf(el);
|
||||||
|
|
||||||
ctx.excluded[field.name] = new Exclude(
|
if (fieldAnn != null) {
|
||||||
canSerialize: cr.read('canSerialize').boolValue,
|
var cr = ConstantReader(fieldAnn);
|
||||||
canDeserialize: cr.read('canDeserialize').boolValue,
|
var sField = SerializableField(
|
||||||
|
alias: cr.peek('alias')?.stringValue,
|
||||||
|
defaultValue: cr.peek('defaultValue')?.objectValue,
|
||||||
|
serializer: cr.peek('serializer')?.symbolValue,
|
||||||
|
deserializer: cr.peek('deserializer')?.symbolValue,
|
||||||
|
errorMessage: cr.peek('errorMessage')?.stringValue,
|
||||||
|
isNullable: cr.peek('isNullable')?.boolValue ?? true,
|
||||||
|
canDeserialize: cr.peek('canDeserialize')?.boolValue ?? false,
|
||||||
|
canSerialize: cr.peek('canSerialize')?.boolValue ?? false,
|
||||||
|
exclude: cr.peek('exclude')?.boolValue ?? false,
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
// Check for @DefaultValue()
|
ctx.fieldInfo[field.name] = sField;
|
||||||
var defAnn =
|
|
||||||
const TypeChecker.fromRuntime(DefaultValue).firstAnnotationOf(el);
|
|
||||||
if (defAnn != null) {
|
|
||||||
var rev = new ConstantReader(defAnn).revive().positionalArguments[0];
|
|
||||||
ctx.defaults[field.name] = rev;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for alias
|
if (sField.defaultValue != null) {
|
||||||
Alias alias;
|
ctx.defaults[field.name] = sField.defaultValue as DartObject;
|
||||||
var aliasAnn = aliasTypeChecker.firstAnnotationOf(el);
|
}
|
||||||
|
|
||||||
if (aliasAnn != null) {
|
if (sField.alias != null) {
|
||||||
alias = new Alias(aliasAnn.getField('name').toStringValue());
|
ctx.aliases[field.name] = sField.alias;
|
||||||
}
|
} else if (autoSnakeCaseNames != false) {
|
||||||
|
ctx.aliases[field.name] = new ReCase(field.name).snakeCase;
|
||||||
|
}
|
||||||
|
|
||||||
if (alias?.name?.isNotEmpty == true) {
|
if (sField.isNullable == false) {
|
||||||
ctx.aliases[field.name] = alias.name;
|
var reason = sField.errorMessage ??
|
||||||
} else if (autoSnakeCaseNames != false) {
|
"Missing required field '${ctx.resolveFieldName(field.name)}' on ${ctx.modelClassName}.";
|
||||||
ctx.aliases[field.name] = new ReCase(field.name).snakeCase;
|
ctx.requiredFields[field.name] = reason;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for @required
|
if (sField.exclude) {
|
||||||
var required =
|
// ignore: deprecated_member_use
|
||||||
const TypeChecker.fromRuntime(Required).firstAnnotationOf(el);
|
ctx.excluded[field.name] = new Exclude(
|
||||||
|
canSerialize: sField.canSerialize,
|
||||||
|
canDeserialize: sField.canDeserialize,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (required != null) {
|
// Apply
|
||||||
var cr = new ConstantReader(required);
|
} else {
|
||||||
var reason = cr.peek('reason')?.stringValue ??
|
// Skip if annotated with @exclude
|
||||||
"Missing required field '${ctx.resolveFieldName(field.name)}' on ${ctx.modelClassName}.";
|
var excludeAnnotation = excludeTypeChecker.firstAnnotationOf(el);
|
||||||
ctx.requiredFields[field.name] = reason;
|
|
||||||
|
if (excludeAnnotation != null) {
|
||||||
|
var cr = new ConstantReader(excludeAnnotation);
|
||||||
|
|
||||||
|
// ignore: deprecated_member_use
|
||||||
|
ctx.excluded[field.name] = new Exclude(
|
||||||
|
canSerialize: cr.read('canSerialize').boolValue,
|
||||||
|
canDeserialize: cr.read('canDeserialize').boolValue,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for @DefaultValue()
|
||||||
|
var defAnn =
|
||||||
|
// ignore: deprecated_member_use
|
||||||
|
const TypeChecker.fromRuntime(DefaultValue).firstAnnotationOf(el);
|
||||||
|
if (defAnn != null) {
|
||||||
|
var rev = new ConstantReader(defAnn).revive().positionalArguments[0];
|
||||||
|
ctx.defaults[field.name] = rev;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for alias
|
||||||
|
// ignore: deprecated_member_use
|
||||||
|
Alias alias;
|
||||||
|
var aliasAnn = aliasTypeChecker.firstAnnotationOf(el);
|
||||||
|
|
||||||
|
if (aliasAnn != null) {
|
||||||
|
// ignore: deprecated_member_use
|
||||||
|
alias = new Alias(aliasAnn.getField('name').toStringValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alias?.name?.isNotEmpty == true) {
|
||||||
|
ctx.aliases[field.name] = alias.name;
|
||||||
|
} else if (autoSnakeCaseNames != false) {
|
||||||
|
ctx.aliases[field.name] = new ReCase(field.name).snakeCase;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for @required
|
||||||
|
var required =
|
||||||
|
const TypeChecker.fromRuntime(Required).firstAnnotationOf(el);
|
||||||
|
|
||||||
|
if (required != null) {
|
||||||
|
var cr = new ConstantReader(required);
|
||||||
|
var reason = cr.peek('reason')?.stringValue ??
|
||||||
|
"Missing required field '${ctx.resolveFieldName(field.name)}' on ${ctx.modelClassName}.";
|
||||||
|
ctx.requiredFields[field.name] = reason;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.fields.add(field);
|
ctx.fields.add(field);
|
||||||
|
|
|
@ -19,7 +19,11 @@ class BuildContext {
|
||||||
/// A map of field names to their default values.
|
/// A map of field names to their default values.
|
||||||
final Map<String, DartObject> defaults = {};
|
final Map<String, DartObject> defaults = {};
|
||||||
|
|
||||||
|
/// A map of fields to their related information.
|
||||||
|
final Map<String, SerializableField> fieldInfo = {};
|
||||||
|
|
||||||
/// A map of fields that have been marked as to be excluded from serialization.
|
/// A map of fields that have been marked as to be excluded from serialization.
|
||||||
|
// ignore: deprecated_member_use
|
||||||
final Map<String, Exclude> excluded = {};
|
final Map<String, Exclude> excluded = {};
|
||||||
|
|
||||||
/// A map of "synthetic" fields, i.e. `id` and `created_at` injected automatically.
|
/// A map of "synthetic" fields, i.e. `id` and `created_at` injected automatically.
|
||||||
|
@ -38,6 +42,9 @@ class BuildContext {
|
||||||
|
|
||||||
final ClassElement clazz;
|
final ClassElement clazz;
|
||||||
|
|
||||||
|
/// Any annotations to include in the generated class.
|
||||||
|
final List<DartObject> includeAnnotations;
|
||||||
|
|
||||||
/// The name of the field that identifies data of this model type.
|
/// The name of the field that identifies data of this model type.
|
||||||
String primaryKeyName = 'id';
|
String primaryKeyName = 'id';
|
||||||
|
|
||||||
|
@ -45,7 +52,8 @@ class BuildContext {
|
||||||
{this.originalClassName,
|
{this.originalClassName,
|
||||||
this.sourceFilename,
|
this.sourceFilename,
|
||||||
this.autoSnakeCaseNames,
|
this.autoSnakeCaseNames,
|
||||||
this.autoIdAndDateFields});
|
this.autoIdAndDateFields,
|
||||||
|
this.includeAnnotations: const <DartObject>[]});
|
||||||
|
|
||||||
/// The name of the generated class.
|
/// The name of the generated class.
|
||||||
String get modelClassName => originalClassName.startsWith('_')
|
String get modelClassName => originalClassName.startsWith('_')
|
||||||
|
|
|
@ -30,6 +30,10 @@ class JsonModelGenerator extends GeneratorForAnnotation<Serializable> {
|
||||||
..name = ctx.modelClassNameRecase.pascalCase
|
..name = ctx.modelClassNameRecase.pascalCase
|
||||||
..annotations.add(refer('generatedSerializable'));
|
..annotations.add(refer('generatedSerializable'));
|
||||||
|
|
||||||
|
for (var ann in ctx.includeAnnotations) {
|
||||||
|
clazz.annotations.add(convertObject(ann));
|
||||||
|
}
|
||||||
|
|
||||||
if (shouldBeConstant(ctx)) {
|
if (shouldBeConstant(ctx)) {
|
||||||
clazz.implements.add(new Reference(ctx.originalClassName));
|
clazz.implements.add(new Reference(ctx.originalClassName));
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -21,10 +21,10 @@ abstract class _Author extends Model {
|
||||||
|
|
||||||
Book get newestBook;
|
Book get newestBook;
|
||||||
|
|
||||||
@exclude
|
@SerializableField(exclude: true)
|
||||||
String get secret;
|
String get secret;
|
||||||
|
|
||||||
@Exclude(canDeserialize: true)
|
@SerializableField(exclude: true, canDeserialize: true)
|
||||||
String get obscured;
|
String get obscured;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +35,8 @@ abstract class _Library extends Model {
|
||||||
|
|
||||||
@Serializable(serializers: Serializers.all)
|
@Serializable(serializers: Serializers.all)
|
||||||
abstract class _Bookmark extends Model {
|
abstract class _Bookmark extends Model {
|
||||||
@exclude
|
|
||||||
|
@SerializableField(exclude: true)
|
||||||
final Book book;
|
final Book book;
|
||||||
|
|
||||||
List<int> get history;
|
List<int> get history;
|
||||||
|
|
|
@ -5,12 +5,18 @@ import 'package:angel_serialize/angel_serialize.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
part 'book.g.dart';
|
part 'book.g.dart';
|
||||||
|
|
||||||
@Serializable(serializers: Serializers.all)
|
@Serializable(
|
||||||
|
serializers: Serializers.all,
|
||||||
|
includeAnnotations: [
|
||||||
|
pragma('hello'),
|
||||||
|
SerializableField(alias: 'omg'),
|
||||||
|
],
|
||||||
|
)
|
||||||
abstract class _Book extends Model {
|
abstract class _Book extends Model {
|
||||||
String author, title, description;
|
String author, title, description;
|
||||||
int pageCount;
|
int pageCount;
|
||||||
List<double> notModels;
|
List<double> notModels;
|
||||||
|
|
||||||
@Alias('camelCase')
|
@SerializableField(alias: 'camelCase')
|
||||||
String camelCaseString;
|
String camelCaseString;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,8 @@ part of angel_serialize.test.models.book;
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
@generatedSerializable
|
@generatedSerializable
|
||||||
|
@pragma('hello')
|
||||||
|
@SerializableField(alias: 'omg')
|
||||||
class Book extends _Book {
|
class Book extends _Book {
|
||||||
Book(
|
Book(
|
||||||
{this.id,
|
{this.id,
|
||||||
|
|
|
@ -4,9 +4,9 @@ part 'goat.g.dart';
|
||||||
|
|
||||||
@Serializable(autoIdAndDateFields: false)
|
@Serializable(autoIdAndDateFields: false)
|
||||||
abstract class _Goat {
|
abstract class _Goat {
|
||||||
@DefaultValue(34)
|
@SerializableField(defaultValue: 34)
|
||||||
int get integer;
|
int get integer;
|
||||||
|
|
||||||
@DefaultValue([34, 35])
|
@SerializableField(defaultValue: [34, 35])
|
||||||
List<int> get list;
|
List<int> get list;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue