Migration and Compatibility topic
dart_mappable is meant as an alternative to other popular serialization and data-class packages. To make migration
away from these easier it provides basic compatibility and configuration options to enable partial migration.
json_serializable
json_serializable is a popular serialization package for simple applications.
There are two migration cases related to this package:
- You want to migrate your own classes to
dart_mappableand away fromjson_serializable. - You want to make (your own or external) classes that use
json_serializablecompatible withdart_mappable.
This also allows for partially migrating only a subset of your classes to dart_mappable while still being able to
include and access your legacy models.
Migrating classes to dart_mappable
To migrate your classes to dart_mappable follow the normal steps outlined in the Models page.
A very important difference between the packages is that the toJson() method returns
- a
Stringindart_mappable, - a
Map<String, dynamic>injson_serializable.
The equivalent in dart_mappable is instead named toMap() to better reflect the return type.
Thereby, dart_mappable provides the following equivalent of methods when coming from json_serializable:
toJson()fromjson_serializableis equivalent totoMap()indart_mappableand returns aMap<String, dynamic>jsonEncode(toJson())fromjson_serializableis equivalent to.toJson()indart_mappableand returns aString
It is recommended that you adapt any code that previously used the toJson() method of any class to instead use toMap().
Because we recognize that this might be tedious for a larger codebase, we provide a faster migration path by allowing
a configuration override to change the naming of the generated methods to the json_serializable way.
To change the naming of the generated methods, add the following to the build.yaml file in your project root:
global_options:
dart_mappable_builder:
options:
# ... other dart_mappable options
renameMethods:
fromJson: fromJsonString
toJson: toJsonString
fromMap: fromJson
toMap: toJson
This generates Map<String, dynamic> toJson() instead of Map<String, dynamic> toMap() and changes other methods accordingly.
Add compatibility for packages requiring json_serializable
By now there are a number of packages on pub.dev that expect the json_serializables version of the toJson() method
when dealing with data classes, for example packages like retrofit or chopper.
To make your data classes using dart_mappable work well with these packages, you need to use the same
renameMethods config as shown above. Additionally, you need to make sure that the dart_mappable code generator runs
before the other code generators of these packages. To do that, adjust your build.yaml to the following:
global_options:
dart_mappable_builder:
runs_before:
# list the generator packages you depend on, e.g.
- retrofit_generator
- chopper_generator
options:
# ... other dart_mappable options, including 'renameMethods'
Add compatibility for classes using json_serializable
Classes using json_serializable always have the same structure:
- A factory constructor
MyClass.fromJson(Map<String, Object?> json)to deserialize an instance of the class, and - A
Map<String, dynamic> toJson()method to serialize an instance of your class.
To use these classes with dart_mappable, you can use the SerializableMapper like this:
void main() {
// Create a compatibe mapper for your class.
var myClassMapper = SerializableMapper<MyClass, Map<String, dynamic>>(
// Pass the 'fromJson' method (without parenteses!).
decode: MyClass.fromJson,
// Pass an arrow function returning the 'toJson' method (without parenteses!).
encode: (myClass) => myClass.toJson,
);
// Make it accessible by all other mappers (Including being used as fields on other classes).
MapperContainer.globals.use(myClassMapper);
}
For generic classes with one or two type parameters, use the SerializableMapper.arg1 or
SerializableMapper.arg2 constructors respectively.
freezed
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:
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 documentation.
You can also add the @MappableField() annotation to any of the fields.
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:
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.
fast_immutable_collections
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:
final iListMapper = SerializableMapper<IList, dynamic>.arg1(
decode: IList.fromJson,
encode: (list) => list.toJson,
type: <E>(f) => f<IList<E>>(),
);
final iMapMapper = SerializableMapper<IMap, Map<String, dynamic>.arg2(
decode: IMap.fromJson,
encode: (map) => map.toJson,
type: <Key, Val>(f) => f<IMap<Key, Val>>(),
);
For a complete working example see the fic_mappable example on github.
Classes
-
SerializableMapper<
T extends Object, V extends Object> Migration and Compatibility - A mapper for handling classes that comply with the json_serializable format.