diff --git a/packages/dart_mappable/README.md b/packages/dart_mappable/README.md index 9d830cf5..6da541fc 100644 --- a/packages/dart_mappable/README.md +++ b/packages/dart_mappable/README.md @@ -234,120 +234,24 @@ The generated `Mappable` mixin will come with the following methods: See the full documentation [here](https://pub.dev/documentation/dart_mappable/latest/topics/Introduction-topic.html) or jump directly to the topic you are looking for: -- [**Models**](https://pub.dev/documentation/dart_mappable/latest/topics/Models-topic.html) show you how to structure and annotate your data models. -- [**Enums**](https://pub.dev/documentation/dart_mappable/latest/topics/Enums-topic.html) show you how to structure and annotate your enums. -- [**Configuration**](https://pub.dev/documentation/dart_mappable/latest/topics/Configuration-topic.html) goes into the different configuration options you have. -- [**Copy-With**](https://pub.dev/documentation/dart_mappable/latest/topics/Copy-With-topic.html) describes the copy-with functionalities and how to use them. -- [**Polymorphism**](https://pub.dev/documentation/dart_mappable/latest/topics/Polymorphism-topic.html) shows how to do polymorphic classes and inheritance. -- [**Generics**](https://pub.dev/documentation/dart_mappable/latest/topics/Generics-topic.html) explain generic decoding and how to use it. -- [**Mapping Hooks**](https://pub.dev/documentation/dart_mappable/latest/topics/Mapping%20Hooks-topic.html) shows how to use hooks to customize your de- and encoding process. -- [**Custom Mappers**](https://pub.dev/documentation/dart_mappable/latest/topics/Custom%20Mappers-topic.html) explains how to set up and use (non-generated) custom mappers. -- [**Mapper Container**](https://pub.dev/documentation/dart_mappable/latest/topics/Mapper%20Container-topic.html) describes the inner workings of mapper containers in more detail. - -## Compatibility - -This package aims to be compatible with other code-generation packages. Check the `examples` directory for some common use-cases. - -### freezed - -[freezed](https://pub.dev/packages/freezed) is a "code generator for unions/pattern-matching/copy"; -With this package, it is easy to create union or sealed classes. - -Here is a simple example taken from their documentation: - -```dart -part 'myfile.freezed.dart'; - -@freezed -class Union with _$Union { - const factory Union(int value) = Data; - const factory Union.loading() = Loading; - const factory Union.error([String? message]) = ErrorDetails; -} -``` - -To make it compatible with dart_mappable, just add your `@MappableClass` annotations to both the parent class, and all **factory constructors**, as if they were the child classes. -For a description of the `discriminatorKey` and `discriminatorValue` properties refer to the [Polymorphism](https://pub.dev/documentation/dart_mappable/latest/topics/Polymorphism-topic.html) documentation. -You can also add the `@MappableField()` annotation to any of the fields. - -```dart -part 'myfile.freezed.dart'; -part 'myfile.mapper.dart'; - -@freezed -@MappableClass(discriminatorKey: 'type') -class Union with _$Union { - @MappableClass(discriminatorValue: 'data') - const factory Union.data(@MappableField(key: 'mykey') int value) = Data; - @MappableClass(discriminatorValue: 'loading') - const factory Union.loading() = Loading; - @MappableClass(discriminatorValue: 'error') - const factory Union.error([String? message]) = ErrorDetails; -} -``` - -This will now allow you to use this and the resulting `Data`, `Loading` and `ErrorDetails` classes as usual: - -```dart -void main() { - var data = Union.data(42); - - var dataJson = data.toJson(); - print(dataJson); // {"mykey":42,"type":"data"} - - var parsedData = UnionMapper.fromJson(dataJson); - print(parsedData); // Union.data(value: 42) -} -``` - -For the full example and generated files, check out the `examples/example_freezed` directory. - -### json_serializable - -[json_serializable](https://pub.dev/packages/json_serializable) is a popular serialization package -for simple applications. While this package was designed as a replacement / alternative for -json_serializable, you may come across situations where you need to deal with classes that either -use this package directly, or are designed to be compatible with it. - -These classes always have the same structure: - -1. A factory constructor `MyClass.fromJson(Map json)` to decode json to an instance of the class, and -2. A `myClass.toJson()` method to encode an instance to json. - -To use these classes with `dart_mappable`, you can use the `SerializableMapper` like this: - -```dart -void main() { - var myClassMapper = SerializableMapper>( - decode: MyClass.fromJson, - encode: (myClass) => myClass.toJson, - ); - // This makes it accessible by all other mappers. - MapperContainer.globals.use(myClassMapper); -} -``` - -For generic classes with one or two type parameters, use the `SerializableMapper.arg1` or -`SerializableMapper.arg2` constructors respectively. - -### fast_immutable_collections - -[fast_immutable_collections](https://pub.dev/packages/fast_immutable_collections) adds immutable -variants for the standard collections types (`List`, `Map`, `Set`). These types are compatible with -`json_serializable`, so we can use the `SerializableMapper` from above as follows: - -```dart -final iListMapper = SerializableMapper.arg1( - decode: IList.fromJson, - encode: (list) => list.toJson, - type: (f) => f>(), -); - -final iMapMapper = SerializableMapper.arg2( -decode: IMap.fromJson, -encode: (map) => map.toJson, -type: (f) => f>(), -); -``` - -For a complete working example see the [fic_mappable example](https://github.com/schultek/dart_mappable/tree/main/examples/fic_mappable) on Github. +- [**Models**](https://pub.dev/documentation/dart_mappable/latest/topics/Models-topic.html) + show you how to structure and annotate your data models. +- [**Enums**](https://pub.dev/documentation/dart_mappable/latest/topics/Enums-topic.html) + show you how to structure and annotate your enums. +- [**Configuration**](https://pub.dev/documentation/dart_mappable/latest/topics/Configuration-topic.html) + goes into the different configuration options you have. +- [**Copy-With**](https://pub.dev/documentation/dart_mappable/latest/topics/Copy-With-topic.html) + describes the copy-with functionalities and how to use them. +- [**Polymorphism**](https://pub.dev/documentation/dart_mappable/latest/topics/Polymorphism-topic.html) + shows how to do polymorphic classes and inheritance. +- [**Generics**](https://pub.dev/documentation/dart_mappable/latest/topics/Generics-topic.html) + explain generic decoding and how to use it. +- [**Mapping Hooks**](https://pub.dev/documentation/dart_mappable/latest/topics/Mapping%20Hooks-topic.html) + shows how to use hooks to customize your de- and encoding process. +- [**Custom Mappers**](https://pub.dev/documentation/dart_mappable/latest/topics/Custom%20Mappers-topic.html) + explains how to set up and use (non-generated) custom mappers. +- [**Mapper Container**](https://pub.dev/documentation/dart_mappable/latest/topics/Mapper%20Container-topic.html) + describes the inner workings of mapper containers in more detail. +- [**Migration and Compatibility**](https://pub.dev/documentation/dart_mappable/latest/topics/Migration%20and%20Compatibility-topic.html) + shows you how you can incrementally migrate from other packages like freezed or json_serializable and use compatible + packages like fast_immutable_collections. diff --git a/packages/dart_mappable/dartdoc_options.yaml b/packages/dart_mappable/dartdoc_options.yaml index ffff405d..26d30d31 100644 --- a/packages/dart_mappable/dartdoc_options.yaml +++ b/packages/dart_mappable/dartdoc_options.yaml @@ -20,6 +20,8 @@ dartdoc: markdown: "doc/custom.md" "Mapper Container": markdown: "doc/container.md" + "Migration and Compatibility": + markdown: "doc/migration.md" categoryOrder: - "Introduction" - "Models" @@ -30,4 +32,5 @@ dartdoc: - "Generics" - "Mapping Hooks" - "Custom Mappers" - - "Mapper Container" \ No newline at end of file + - "Mapper Container" + - "Migration and Compatibility" diff --git a/packages/dart_mappable/doc/migration.md b/packages/dart_mappable/doc/migration.md new file mode 100644 index 00000000..70198b8d --- /dev/null +++ b/packages/dart_mappable/doc/migration.md @@ -0,0 +1,113 @@ +`dart_mappable` tries to be compatible with other code-generation packages. Check the `examples` directory for some +common use-cases. Following are some popular packages that you can use together with `dart_mappable`. + +### freezed + +[freezed](https://pub.dev/packages/freezed) is a "code generator for unions/pattern-matching/copy"; +With this package, it is easy to create union or sealed classes. + +While `dart_mappable` can do everything freezed can do and more, it provides compatibility to give you an easy migration +path when you are considering switching to `dart_mappable`. + +Here is a simple model taken from `freezed` readme: + +```dart +part 'myfile.freezed.dart'; + +@freezed +class Union with _$Union { + const factory Union(int value) = Data; + const factory Union.loading() = Loading; + const factory Union.error([String? message]) = ErrorDetails; +} +``` + +To make it compatible with dart_mappable, just add your `@MappableClass` annotations to both the parent class, and all **factory constructors**, as if they were the child classes. +For a description of the `discriminatorKey` and `discriminatorValue` properties refer to the [Polymorphism](https://pub.dev/documentation/dart_mappable/latest/topics/Polymorphism-topic.html) documentation. +You can also add the `@MappableField()` annotation to any of the fields. + +```dart +part 'myfile.freezed.dart'; +part 'myfile.mapper.dart'; + +@freezed +@MappableClass(discriminatorKey: 'type') +class Union with _$Union { + @MappableClass(discriminatorValue: 'data') + const factory Union.data(@MappableField(key: 'mykey') int value) = Data; + @MappableClass(discriminatorValue: 'loading') + const factory Union.loading() = Loading; + @MappableClass(discriminatorValue: 'error') + const factory Union.error([String? message]) = ErrorDetails; +} +``` + +This will now allow you to use this and the resulting `Data`, `Loading` and `ErrorDetails` classes as usual: + +```dart +void main() { + var data = Union.data(42); + + var dataJson = data.toJson(); + print(dataJson); // {"mykey":42,"type":"data"} + + var parsedData = UnionMapper.fromJson(dataJson); + print(parsedData); // Union.data(value: 42) +} +``` + +For the full example and generated files, check out the `examples/example_freezed` directory. + +### json_serializable + +[json_serializable](https://pub.dev/packages/json_serializable) is a popular serialization package +for simple applications. + +While this package was designed as a replacement / alternative for `json_serializable`, you may come across +situations where you need to deal with classes that either use this package directly, or are designed to be compatible with it. + +Also when you want to switch from `json_serializable` to `dart_mappable`, you have an easy migration path where you can +start by only partly migrating models over to `dart_mappable` while still having full access to your *legacy* models. + +Classes using `json_serializable` always have the same structure: + +1. A factory constructor `MyClass.fromJson(Map json)` to decode json to an instance of the class, and +2. A `myClass.toJson()` method to encode an instance to json. + +To use these classes with `dart_mappable`, you can use the `SerializableMapper` like this: + +```dart +void main() { + var myClassMapper = SerializableMapper>( + decode: MyClass.fromJson, + encode: (myClass) => myClass.toJson, + ); + // This makes it accessible by all other mappers. + MapperContainer.globals.use(myClassMapper); +} +``` + +For generic classes with one or two type parameters, use the `SerializableMapper.arg1` or +`SerializableMapper.arg2` constructors respectively. + +### fast_immutable_collections + +[fast_immutable_collections](https://pub.dev/packages/fast_immutable_collections) adds immutable +variants for the standard collections types (`List`, `Map`, `Set`). These types are compatible with +`json_serializable`, so we can use the `SerializableMapper` from above as follows: + +```dart +final iListMapper = SerializableMapper.arg1( + decode: IList.fromJson, + encode: (list) => list.toJson, + type: (f) => f>(), +); + +final iMapMapper = SerializableMapper.arg2( +decode: IMap.fromJson, +encode: (map) => map.toJson, +type: (f) => f>(), +); +``` + +For a complete working example see the [fic_mappable example](https://github.com/schultek/dart_mappable/tree/main/examples/fic_mappable) on github. diff --git a/packages/dart_mappable/lib/src/mappers/default_mappers.dart b/packages/dart_mappable/lib/src/mappers/default_mappers.dart index daab9b1a..6aeeaebd 100644 --- a/packages/dart_mappable/lib/src/mappers/default_mappers.dart +++ b/packages/dart_mappable/lib/src/mappers/default_mappers.dart @@ -88,6 +88,8 @@ typedef TypeFactory2 = Object? Function(Object? Function() f); /// A mapper for handling classes that comply with the json_serializable format. /// /// This mapper expects a `fromJson` and `toJson` method on a given class. +/// +/// {@category Migration and Compatibility} class SerializableMapper extends MapperBase with PrimitiveMethodsMixin { late T Function(V value, DecodingContext context) _decoder;