Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/schultek/dart_mappable

Improved json serialization and data classes with full support for generics, inheritance, customization and more.
https://github.com/schultek/dart_mappable

dart hacktoberfest

Last synced: 12 days ago
JSON representation

Improved json serialization and data classes with full support for generics, inheritance, customization and more.

Awesome Lists containing this project

README

        

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 advances 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](https://github.com/schultek/dart_mappable).)*

## Quick Start

First, add `dart_mappable` as a dependency, together with `dart_mappable_builder` and `build_runner` as a dev_dependency.

```shell script
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:

```dart
// 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 an 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`) make sure to also provide all type parameters
to the mixin (`... with MyClassMappable`).*

---

In order to generate the serialization code, run the following command:

```shell script
dart pub 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 pub run build_runner watch`.*

This will generate a `.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:

1. Through the generated `Mapper` classes, and
2. through the methods defined by the generated mixin.

```dart
...

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 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` 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](https://pub.dev/documentation/dart_mappable/latest/topics/Migration%20and%20Compatibility-topic.html)*.

## 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.

```dart
@MappableClass()
class MyClass with MyClassMappable { ... }

@MappableEnum()
enum MyEnum { ... }
```

***Tip**: Check out the documentation about
[Models](https://pub.dev/documentation/dart_mappable/latest/topics/Models-topic.html) and
[Enums](https://pub.dev/documentation/dart_mappable/latest/topics/Enums-topic.html).*

For deserialization, `dart_mappable` will use the first available constructor of a class, but you
can use a specific constructor using the `@MappableConstructor()` annotation.

```dart
@MappableClass()
class MyClass with MyClassMappable {
MyClass(); // Don't use this

@MappableConstructor()
MyClass.special(); // Use this
}
```

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.

```dart
@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](https://pub.dev/documentation/dart_mappable/latest/topics/Models-topic.html#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](https://pub.dev/documentation/dart_mappable/latest/topics/Mapping%20Hooks-topic.html).*

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.

```dart
@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](https://pub.dev/documentation/dart_mappable/latest/topics/Configuration-topic.html) options.*

---

Here are again all **six** annotations that you can use in your code:

1. `@MappableClass()` can be used on a class to specify options like the `caseStyle` of the json keys, whether to ignore null values, or [hooks](https://pub.dev/documentation/dart_mappable/latest/topics/Mapping%20Hooks-topic.html).
2. `@MappableConstructor()` can be used on a constructor to mark this to be used for decoding. It has no properties.
3. `@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](https://pub.dev/documentation/dart_mappable/latest/topics/Mapping%20Hooks-topic.html).
4. `@MappableEnum()` can be used on an enum to specify the `mode` or `caseStyle` of the encoded enum values, or the `defaultValue`.
5. `@MappableValue()` can be used on an enum value to specify a custom encoded value to use.
6. `@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:

- `Mapper.fromMap(Map map)` will take an encoded map object and return a decoded object of type `ClassName`.
- `Mapper.fromJson(String json)` internally uses `fromMap` but works with json encoded `String`s.

***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 `Mappable` mixin will come with the following methods:

- `toMap()` and `toJson()`.
- `copyWith()` to create copies of your class instance (see [Copy With](https://pub.dev/documentation/dart_mappable/latest/topics/Copy-With-topic.html)).
- overrides for `operator ==`, `hashCode` and `toString()`.

## Full Documentation

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.
- [**Records**](https://pub.dev/documentation/dart_mappable/latest/topics/Records-topic.html)
show you how to use records as part of your models.
- [**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.