dart_mappable
v4.10.0Improved json serialization and data classes with full support for generics, inheritance, customization and more.
Архив пакета: https://pubdev.letsnova.ru/api/archives/dart_mappable/4.10.0.tar.gz
dart pub add dart_mappableREADME
dart_mappable
Quickstart • Documentation • Example • Package Comparison
Improved json serialization and data classes with
full support for generics, inheritance, customization and more.
dart_mappable covers all basic features (from/to json, == override, hashCode, toString(), copyWith)
while adding new or improved support for advanced use-cases including generics, inheritance and
polymorphism, customization and more.
- 🎁 Everything included: Serialization, Equality, ToString, CopyWith and more.
- 🚀 Excels at complexity: It handles generics, polymorphism and multi-inheritance with ease.
- 🎛️ Highly flexible: Customize the serialization, add custom types or integrate with other packages.
- 🔥 No compromises: Its promise is that it just works, no matter what classes you throw at it.
(If you find an unsupported case, you get a cookie 🍪. And please add an issue on github.)
Quick Start
First, add dart_mappable as a dependency, together with dart_mappable_builder and build_runner as a dev_dependency.
flutter pub add dart_mappable
flutter pub add build_runner --dev
flutter pub add dart_mappable_builder --dev
Next annotate your classes that you want to use with @MappableClass() and add the
appropriate part directive to include the generated .mapper.dart file:
// This file is "model.dart"
import 'package:dart_mappable/dart_mappable.dart';
// Will be generated by dart_mappable
part 'model.mapper.dart';
@MappableClass()
class MyClass with MyClassMappable {
final int myValue;
MyClass(this.myValue);
}
To use a class you must:
- annotate the class with
@MappableClass()and - apply a mixin with the name of the class plus
Mappable.
Tip: Don't worry if the mixin don't exist at first, just run code-generation once and it will be created. The builder will also warn you if you define your class without the proper mixin.
Note: For generic classes (e.g. MyClass<T>) make sure to also provide all type parameters
to the mixin (... with MyClassMappable<T>).
In order to generate the serialization code, run the following command:
dart run build_runner build
Tip: You'll need to re-run code generation each time you are making changes to your annotated classes.
During development, you can use watch to automatically watch your changes: dart run build_runner watch.
This will generate a <filename>.mapper.dart file for each of your files containing annotated classes.
Last step is to use the generated mappers. There are two main ways to interact with your models using this package:
- Through the generated
<ClassName>Mapperclasses, and - through the methods defined by the generated mixin.
...
void main() {
// Decode a [Map] using the [MyClassMapper] class:
MyClass myClass = MyClassMapper.fromMap({'myValue': 123});
// Or decode directly from json:
MyClass myClass2 = MyClassMapper.fromJson('{"myValue": 123}');
// Encode an instance of your class using the methods provided by the mixin:
Map<String, dynamic> map = myClass.toMap();
String json = myClass.toJson();
// There are also implementations generated for [operator ==], [hashCode] and [toString]:
bool thisIsTrue = (myClass == myClass2);
print(myClass);
// Last you can use [copyWith] to create a copy of an object:
MyClass myClass3 = myClass.copyWith(myValue: 0);
}
Beware: The .toJson() method returns a String. If you are migrating from json_serializable, you might
be used to this returning a Map<String, dynamic> instead. Make sure to properly adapt your code to this change,
as not doing so might lead to unexpected behavior. Find more about the recommended migration path
here.
Overview
To setup, annotate your model classes with @MappableClass() and your enums with @MappableEnum().
Each annotation has a set of properties to configure the generated code.
@MappableClass()
class MyClass with MyClassMappable { ... }
@MappableEnum()
enum MyEnum { ... }
Tip: Check out the documentation about Models and Enums.
For deserialization, dart_mappable will use the first available constructor of a class (or the primary constructor if present), but you
can use a specific constructor using the @MappableConstructor() annotation.
@MappableClass()
class MyClass with MyClassMappable {
MyClass(); // Don't use this
@MappableConstructor()
MyClass.special(); // Use this
}
Dart's primary constructors are also fully supported:
@MappableClass()
class MyClass(final String name, {final int age = 20}) with MyClassMappable;
You can also annotate a single field or constructor parameter of a class using @MappableField()
to set a specific json key or add custom hooks.
@MappableClass()
class MyClass with MyClassMappable {
MyClass(this.value);
@MappableField(key: 'my_key')
String value;
}
Note: This can only be used on a field if it is directly assigned as a constructor parameter (MyClass(this.myField)).
Setting this annotation on any other field will have no effect.
(Read Utilizing Constructors for an explanation why this is.)
Tip: Hooks are a way to customize the serialization of any field or class. Read more in the documentation about Mapping Hooks.
You can add the @MappableLib() annotation to your library statement to set a default configuration
for all included classes and enums, e.g. the case style for json keys.
@MappableLib(caseStyle: CaseStyle.camelCase) // will be applied to all classes
library model;
part 'model.mapper.dart';
@MappableClass() // no need to set caseStyle here
class MyClass with MyClassMappable {
...
}
Tip: Check out the documentation to see all available Configuration options.
Here are again all six annotations that you can use in your code:
@MappableClass()can be used on a class to specify options like thecaseStyleof the json keys, whether to ignore null values, or hooks.@MappableConstructor()can be used on a constructor to mark this to be used for decoding. It has no properties.@MappableField()can be used on a constructor parameter or a field to specify a json key to be used instead of the field name, or hooks.@MappableEnum()can be used on an enum to specify themodeorcaseStyleof the encoded enum values, or thedefaultValue.@MappableValue()can be used on an enum value to specify a custom encoded value to use.@MappableLib()can be used on a library statement or import / export statement to set a default configuration for the annotated library or include / exclude classes.
Mapper Interface
dart_mappable will generate Mapper classes that provide these methods or properties:
<ClassName>Mapper.fromMap<T>(Map<String, dynamic> map)will take an encoded map object and return a decoded object of typeClassName.<ClassName>Mapper.fromJson<T>(String json)internally usesfromMapbut works with json encodedStrings.
Tip: If you prefer to use MyClass.fromJson over MyClassMapper.fromJson, add the fromJson and
fromMap methods directly to your class like this:
class MyClass with MyClassMappable {
...
static final fromMap = MyClassMapper.fromMap;
static final fromJson = MyClassMapper.fromJson;
}
The generated <ClassName>Mappable mixin will come with the following methods:
toMap()andtoJson().copyWith()to create copies of your class instance (see Copy With).- overrides for
operator ==,hashCodeandtoString().
Full Documentation
See the full documentation here or jump directly to the topic you are looking for:
- Models show you how to structure and annotate your data models.
- Enums show you how to structure and annotate your enums.
- Records show you how to use records as part of your models.
- Configuration goes into the different configuration options you have.
- Copy-With describes the copy-with functionalities and how to use them.
- Polymorphism shows how to do polymorphic classes and inheritance.
- Generics explain generic decoding and how to use it.
- Mapping Hooks shows how to use hooks to customize your de- and encoding process.
- Custom Mappers explains how to set up and use (non-generated) custom mappers.
- Mapper Container describes the inner workings of mapper containers in more detail.
- Migration and Compatibility shows you how you can incrementally migrate from other packages like freezed or json_serializable and use compatible packages like fast_immutable_collections.
История изменений
4.10.0
- Add support for Primary Constructors.
4.8.0
- Bump
analyzerto>=10.0.0 <12.0.0.
4.7.0
- Added
firstWheretoListCopyWithfor chaining copyWith calls on a list element based on a predicate function. - Add
useNodocoption for excluding generated classes from dartdoc output.
4.6.1
- Record mappers now correctly uses hooks specified on the
@MappableRecordannotation. - Nested records are now correctly initialized, and record mappers are included in the generated
initializeMappers()method. - Getters are no longer falsely used in equality or stringify methods.
4.6.0
- Add support for self-referencing generics (e.g.
T extends Comparable<T>) - Fix handling of nullable function fields.
- Disable formatting of generated files through
// dart format off. - Require
sdk: >=3.7.0.
4.5.0
- Added
shallowEncodingoption to@MappableClass(). - Added
includeTypeIdoption to@MappableClass().
4.4.0
- Require
sdk: >=3.6.0.
4.3.1
- Added
MapperContainer.typeIdKeyto support changing the '__type' key.
4.3.0
- Added support for reusing annotations as constant variables.
- Added
SimpleMapper1BoundedandSimpleMapper2Boundedfor custom bounded generic types. - Fixed generation for generic functions.
- Fixed bug with nullable generic field.
- Fixed bug with import path on windows.
4.2.2
- Added
CaseStyle.upperSnakeCase. - Fixed issues with adding unnecessary '__type' property for nullable generics.
- Improved serialization consistency and equality handling.
4.2.1
- Performance improvements.
- Updated docs.
4.2.0
- Added custom typedef for mapping fields to resolve naming conflict.
- Deprecated creating and linking custom
MapperContainers. If you are affected by this see https://github.com/schultek/dart_mappable/issues/159.
4.1.0
- Added support for shallow encoding a class:
MyClassMapper.ensureInitialized().encodeMap<MyClass>(myClass, EncodingOptions(shallow: true))
- Correctly escape
$in class names. - Added option to use unordered list equality with iterables:
IterableMapper.equalityMode = IterableEqualityMode.unordered
- Added
build_extensionsoption to builder configuration.
4.0.1
- Added support for generic typed parameters for deep copyWith.
4.0.0
-
Require
sdk: >=3.0.0. -
Added support for Records.
-
Fields of a class can now be any record type.
-
You can annotate toplevel record typedefs:
@MappableRecord() typedef Coordinates = ({double latitude, double longitude});
For a more detailed usage see the documentation.
-
3.3.1
- Improved migration docs regarding
json_serializableand the difference oftoJson().
3.3.0
- Make
DateTimeencoding configurable throughDateTimeMapper.encodingMode.
3.2.0
- Handle bounded nested type parameters in subclasses.
3.1.3
- Fixed set equality.
3.1.2
- Fixed unexpected type error when decoding
null.
3.1.1
- Fixed supporting expressions in
@MappableClass.includeCustomMappers.
3.1.0
-
Fixed error when using non-literal values in
@MappableValue(). -
The builder now respects basic initializer expressions of a constructor. This makes it possible to do field renaming or assigning to private fields without requiring an additional getter matching the parameter.
The following is now supported out of the box:
class MyClass { MyClass(int value, {String? name}) // Effectively renaming 'value' to 'data'. : data = value, // Assigning to a private field + having a null fallback. _name = name ?? 'Unnamed'; final int value; final String _name; -
Fixed encoding of a map now returns a
Map<String, dynamic>where possible (instead of aMap<dynamic, dynamic>)
3.0.1
- Fixed dependency conflict with
package:collection. - Added topics for pub.dev.
3.0.0
-
Breaking: Generated mappers no longer have a
.containerproperty. This was removed in favor of the newMapperContainer.globalscontainer.// Instead of this: var value = MyClassMapper.container.fromValue(...); // Do this: var value = MapperContainer.globals.fromValue(...);Mapper initialization and usage is now simplified to the following:
- When used explicitly (e.g. through
MyClassMapper.fromMapormyClass.toMap()) no additional initialization is needed. - When used implicitly (through a generic type e.g.
MapperContainer.globals.fromMap<MyClass>()) the mapper needs to be initialized once before being used withMyClassMapper.ensureInitialized().
- When used explicitly (e.g. through
-
Breaking: Changed internal mapper implementation which causes any custom mapper to break.
- Removed
MapperElementBaseclass. - Added
MappingContextbeing passed to mapper methods.
See docs on how to use custom mappers in v3.
- Removed
-
Breaking: Removed
@MappableLib.createCombinedContainerin favor of@MappableLib.generateInitializerForScope.Instead of generating a new container, v3 generates an initialization function for all mappers. Use it early on in your application:
@MappableLib(generateInitializerForScope: InitializerScope.package) library main; import 'main.init.dart'; void main() { initializeMappers(); ... } -
Breaking: Improved support and features for
.copyWith.- Copy-With now supports classes that implement multiple interfaces.
- Renamed
.copyWith.apply()method to.copyWith.$update(). - Added
.copyWith.$merge()and.copyWith.$delta().
You can now use
.copyWithwith either an existing instance using.$mergeor a map of values using.$delta.@MappableClass() class A with AMappable { A(this.a, this.b); int? a; int? b; } void main() { var a = A(1, null); var c = a.copyWith.$merge(A(null, 2)); assert(c == A(1, 2)); var d = a.copyWith.$delta({'b': 2}); assert(d == A(1, 2)); } -
Breaking: Removed
CheckTypesHookin favor of discriminator functions.You can now use a custom predicate function as the
discriminatorValueof a class. This function can check whether the encoded value should be decoded to this subclass and return a boolean.@MappableClass() abstract class A with AMappable { A(); } @MappableClass(discriminatorValue: B.checkType) class B extends A with BMappable { B(); /// checks if [value] should be decoded to [B] static bool checkType(value) { return value is Map && value['isB'] == true; } } @MappableClass(discriminatorValue: C.checkType) class C extends A with CMappable { C(); /// checks if [value] should be decoded to [C] static bool checkType(value) { return value is Map && value['isWhat'] == 'C'; } } -
Added support for serializing fields that are not part of the constructor when annotated with
@MappableField(). -
Added
EncodingOptionstotoValuemethod. -
Added support for third-party models by using annotated
typedefs. -
Added
renameMethodsto build options. -
Improved performance of generated encoding and decoding methods.
For a detailed migration guide, see this issue.
2.0.3
- Fixed typo in readme (by @timmaffett)
- Fixed generated container for private libraries.
2.0.2
- Fixed yet another unresolved type bug.
2.0.1
- Fixed unresolved type bug with custom mappers.
2.0.0
-
Mappers are now generated for each file containing annotated classes. This removes the need to specify entry points in the
build.yaml.This is now similar to how packages like
json_serializableorfreezedgenerate code.- Generated files are now
partfiles and need to be included as such. - All annotated classes must now use their respective
<MyClass>Mappablemixin. - Instead of one global
Mappereach class has its own<ClassName>Mapper.- A new global container that includes all models can now be generated using
@MappableLib(createCombinedContainer: true).
- A new global container that includes all models can now be generated using
- Mappers can be linked together to enable working with multiple classes.
- Removed
@CustomMapperannotation in favor ofincludeCustomMappersproperty on@MappableClass().
For a detailed migration guide, see this issue.
- Generated files are now
-
Documentation is now separated from the README using the official pub.dev documentation topics. Find the new documentation here
-
Improvements in performance and support for generics and inheritance.
-
Added the [CheckTypesHook] to allow for custom discriminator checks on subclasses in a polymorphic class structure.
-
CopyWith is now more powerful and also works for generic or polymorphic classes, while being completely type-safe.
When called on a superclass, the concrete subtype will be retained through a
.copyWithcall, which also respects generics:// with `class A` and `class B<T> extends A` A a = B<int>(); // static type A, dynamic type B<int> // signature will be `A copyWith()`, so static type A A a2 = a.copyWith(); // this will still resolve to a dynamic type of B<int> assert(a2 is B<int>);
1.2.0
- Added support for
2.17super parameters
1.1.2
- Improved Readme for constructor utilization
- Fixed missing imports for custom hooks
1.1.1
- Updated description
1.1.0
- Added support for custom enum values
- Choose between
ValuesMode.namedandValuesMode.indexedfor automatic generation of encoded values - Use
@MappableValue(myCustomValue)on an enum value to specify a custom encoded value - Deprecated the
String toStringValue()extension method in favor of the more generaldynamic toValue()
- Choose between
1.0.3
- Fixed issue with minified standard types on web
1.0.2
- Fixed unrecognized type issue for
equals,hashCodeandtoStringmethods
1.0.1
- Improved resolving of constructor parameters, which fixed various issues
in
copyWithandtoMapmethods - Now printing comprehensive warning in the builder output if a parameter cannot be resolved
1.0.0
-
Large refactoring and restructuring
- Restructured builder implementation
- Moved code out of generated files into package
- Split package int
dart_mappableanddart_mappable_builder
-
Mapperis now a singleton classfromValue,toValueand all other methods are now instance methods accessible withMapper.i.fromValue()- the legacy static methods are still available, but forward to the instance methods
-
Improved Readme, added How to use section and documented
copyWithfunctionalities -
Added
@MappableLib()annotation and moved library-level configuration logic from build options to annotation properties -
Switched to using the
type_pluspackage for internal handling of generics -
Added
ChainedHooks,UnescapeNewlinesHooksandEmptyToNullHooks -
Added descriptive and comprehensible exception handling
0.9.1
- Fixed README
0.9.0
- Changed implementation of UnmappedPropertiesHook to allow target parameter at any position in constructor
0.8.7
- Added support for lists in copyWith chains
0.8.6
- Fixed bug in isEquals method
0.8.5
- Restructured and improved tests
0.8.4
- Added get, getAll and useAll methods to Mapper
0.8.3
- Fixed unmapped properties hook
0.8.2
- Fixed enum caseStyle bug
0.8.1
- Fixed missing copyWith implementation bug
0.8.0
- Use CaseStyle in annotations
- Respect null in copyWith methods
- Chained copyWith methods
0.7.2
- Fix equals bug
0.7.1
- Deep equality for lists and maps
0.7.0
- Update license
0.6.5
- Fixed imports on windows
0.6.4
- Upgrade dependencies
0.6.3
- Fixed missing default values of constructor parameters
0.6.2
- Added support for factory constructors and sealed classes
- Added example for usage with freezed package
0.6.1
- Fixed imports issue
- Fixed platform analysis
0.6.0
- Removed usage-support as dev_dependency in favor of safer generation
0.5.1
- Added @CustomMapper annotation to auto-add custom mappers without needing to do
Mapper.use - Fixed decoding issue with nullable types
- Added missing documentation comments
0.5.0
- Reworked configuration system - build.yaml now only support global and library level options
- Added support for disabling generation of single methods
- Simplified CustomMappers
- Improved documentation
0.4.6
- Changed code generation to handle polymorphism explicitly (using switch statement)
- Fixed issue with multiple levels of inheritance
0.4.5
- Added default enum values
0.4.4
- Added support for class-specific hooks
0.4.3
- Subclasses now inherit field annotations
0.4.2
- Added support for encoding/decoding hooks
0.4.1
- Added support for null and default discriminators
- Fixed toString generation
discriminatorValuecan now be any constant expression
0.4.0
- Added support for annotations
- Added some initial tests
0.3.8
- Added support for custom discriminator values
0.3.7
- Added support for custom iterables and maps
- Improved documentation on decoding lists, sets and maps
0.3.6
- Added support for abstract classes and polymorphism using type discriminators
0.3.5
- Fixed minified types issue on web
0.3.4
- Ignore classes with only private constructors
0.3.3
- Changed auto_apply to none
0.3.2
- Added support for DateTime
0.3.1
- Conditionally apply ignoreNull
0.3.0
- Generic type support
- Improved documentation
0.2.1+1
- Fixed formatting
- Export BuildOptions and CaseStyle classes
0.2.1
- Added support for
.toString(),==andhashCodeusing theMappablemixin
0.2.0+1
- Changed builder signature
0.2.0
- Support null-safety
- Added code documentation
0.1.1+1
- Improved example
- Improved README
0.1.1
- Added initial documentation to README
- Added yaml configuration options
0.1.0
- Initial development release
