diff --git a/packages/serialize/angel_serialize_generator/CHANGELOG.md b/packages/serialize/angel_serialize_generator/CHANGELOG.md index ebea7d8d..65be5902 100644 --- a/packages/serialize/angel_serialize_generator/CHANGELOG.md +++ b/packages/serialize/angel_serialize_generator/CHANGELOG.md @@ -1,5 +1,10 @@ # Change Log +## 8.0.1 + +* Fixed `JsonModelGenerator` from generating duplicated fields +* Fixed `JsonModelGenerator` to priortize `id` field as the first argument + ## 8.0.0 * Require Dart >= 3.0 diff --git a/packages/serialize/angel_serialize_generator/lib/build_context.dart b/packages/serialize/angel_serialize_generator/lib/build_context.dart index 91436cc9..fe9eb120 100644 --- a/packages/serialize/angel_serialize_generator/lib/build_context.dart +++ b/packages/serialize/angel_serialize_generator/lib/build_context.dart @@ -56,16 +56,37 @@ Future buildContext( annotation.peek('includeAnnotations')?.listValue ?? [], ); // var lib = await resolver.libraryFor(buildStep.inputId); - var fieldNames = []; var fields = []; + var fieldNames = []; + + for (var field in fields) { + fieldNames.add(field.name); + } // Crawl for classes from parent classes. void crawlClass(InterfaceType? t) { while (t != null) { - fields.insertAll(0, t.element.fields); + // Check and skip fields with same name + var parentClassFields = []; + for (var el in t.element.fields) { + if (fieldNames.contains(el.name)) { + continue; + } + parentClassFields.add(el); + fieldNames.add(el.name); + } + + fields.insertAll(0, parentClassFields); t.interfaces.forEach(crawlClass); t = t.superclass; } + + // Move id field to the front if exist + var item = fields.firstWhereOrNull((el) => el.name == 'id'); + if (item != null) { + fields.removeWhere((el) => el.name == 'id'); + fields.insert(0, item); + } } crawlClass(clazz.thisType); @@ -79,7 +100,7 @@ Future buildContext( if (field.getter != null && (field.setter != null || field.getter!.isAbstract)) { var el = field.setter == null ? field.getter! : field; - fieldNames.add(field.name); + //fieldNames.add(field.name); // Check for @SerializableField var fieldAnn = serializableFieldTypeChecker.firstAnnotationOf(el); diff --git a/packages/serialize/angel_serialize_generator/pubspec.yaml b/packages/serialize/angel_serialize_generator/pubspec.yaml index 1b705f4d..5a4d75e1 100644 --- a/packages/serialize/angel_serialize_generator/pubspec.yaml +++ b/packages/serialize/angel_serialize_generator/pubspec.yaml @@ -1,5 +1,5 @@ name: angel3_serialize_generator -version: 8.0.0 +version: 8.0.1 description: Angel3 model serialization generators, designed for use with Angel. Combine with angel_serialize for flexible modeling. homepage: https://angel3-framework.web.app/ repository: https://github.com/dukefirehawk/angel/tree/master/packages/serialize/angel_serialize_generator diff --git a/packages/serialize/angel_serialize_generator/test/models/character.dart b/packages/serialize/angel_serialize_generator/test/models/character.dart new file mode 100644 index 00000000..5c0eb088 --- /dev/null +++ b/packages/serialize/angel_serialize_generator/test/models/character.dart @@ -0,0 +1,5 @@ +abstract class Character { + String? get id; + + String? get name; +} diff --git a/packages/serialize/angel_serialize_generator/test/models/droid.dart b/packages/serialize/angel_serialize_generator/test/models/droid.dart new file mode 100644 index 00000000..35207673 --- /dev/null +++ b/packages/serialize/angel_serialize_generator/test/models/droid.dart @@ -0,0 +1,12 @@ +import 'package:angel3_serialize/angel3_serialize.dart'; + +import 'character.dart'; + +part 'droid.g.dart'; + +@serializable +abstract class _Droid extends Model implements Character { + String get position; + + num get age; +} diff --git a/packages/serialize/angel_serialize_generator/test/models/droid.g.dart b/packages/serialize/angel_serialize_generator/test/models/droid.g.dart new file mode 100644 index 00000000..d1a1bd1f --- /dev/null +++ b/packages/serialize/angel_serialize_generator/test/models/droid.g.dart @@ -0,0 +1,171 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'droid.dart'; + +// ************************************************************************** +// JsonModelGenerator +// ************************************************************************** + +@generatedSerializable +class Droid extends _Droid { + Droid({ + this.id, + this.createdAt, + this.updatedAt, + this.name, + required this.position, + required this.age, + }); + + @override + String? id; + + /// The time at which this item was created. + @override + DateTime? createdAt; + + /// The last time at which this item was updated. + @override + DateTime? updatedAt; + + @override + String? name; + + @override + String position; + + @override + num age; + + Droid copyWith({ + String? id, + DateTime? createdAt, + DateTime? updatedAt, + String? name, + String? position, + num? age, + }) { + return Droid( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + name: name ?? this.name, + position: position ?? this.position, + age: age ?? this.age); + } + + @override + bool operator ==(other) { + return other is _Droid && + other.id == id && + other.createdAt == createdAt && + other.updatedAt == updatedAt && + other.name == name && + other.position == position && + other.age == age; + } + + @override + int get hashCode { + return hashObjects([ + id, + createdAt, + updatedAt, + name, + position, + age, + ]); + } + + @override + String toString() { + return 'Droid(id=$id, createdAt=$createdAt, updatedAt=$updatedAt, name=$name, position=$position, age=$age)'; + } + + Map toJson() { + return DroidSerializer.toMap(this); + } +} + +// ************************************************************************** +// SerializerGenerator +// ************************************************************************** + +const DroidSerializer droidSerializer = DroidSerializer(); + +class DroidEncoder extends Converter { + const DroidEncoder(); + + @override + Map convert(Droid model) => DroidSerializer.toMap(model); +} + +class DroidDecoder extends Converter { + const DroidDecoder(); + + @override + Droid convert(Map map) => DroidSerializer.fromMap(map); +} + +class DroidSerializer extends Codec { + const DroidSerializer(); + + @override + DroidEncoder get encoder => const DroidEncoder(); + @override + DroidDecoder get decoder => const DroidDecoder(); + static Droid fromMap(Map map) { + return Droid( + id: map['id'] as String?, + createdAt: map['created_at'] != null + ? (map['created_at'] is DateTime + ? (map['created_at'] as DateTime) + : DateTime.parse(map['created_at'].toString())) + : null, + updatedAt: map['updated_at'] != null + ? (map['updated_at'] is DateTime + ? (map['updated_at'] as DateTime) + : DateTime.parse(map['updated_at'].toString())) + : null, + name: map['name'] as String?, + position: map['position'] as String, + age: map['age'] as num); + } + + static Map toMap(_Droid? model) { + if (model == null) { + throw FormatException("Required field [model] cannot be null"); + } + return { + 'id': model.id, + 'created_at': model.createdAt?.toIso8601String(), + 'updated_at': model.updatedAt?.toIso8601String(), + 'name': model.name, + 'position': model.position, + 'age': model.age + }; + } +} + +abstract class DroidFields { + static const List allFields = [ + id, + createdAt, + updatedAt, + name, + position, + age, + ]; + + static const String id = 'id'; + + static const String createdAt = 'created_at'; + + static const String updatedAt = 'updated_at'; + + static const String name = 'name'; + + static const String position = 'position'; + + static const String age = 'age'; +} diff --git a/pubspec.yaml b/pubspec.yaml index eb689c93..77083923 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,4 +4,4 @@ environment: sdk: '>=2.18.0 <3.0.0' dependencies: - melos: 3.0.0 + melos: ^3.1.0