@encoder / @decoder
Setup encoding and decoding for custom data types.
With the @encoder
and @decoder
annotations you can set up custom serialization for any type. This is used
by Jaspr for both:
Usage
To enable custom serialization for your data class use the annotations in the following way:
-
The
@decoder
annotation must be used on a constructor or static method that returns an instance of the class and has exactly one parameter of any primitive serializable type (bool
,int
,String
, etc.). -
The
@encoder
annotation must be used on an instance method that returns the same type that the@decoder
method takes in. -
Both methods can have any name.
In practice this can look like this:
class Model {
// Constructors, fields, etc.
/* ... */
@decoder
static Model decode(Map<String, dynamic> data) => /* ... */;
@encoder
Map<String, dynamic> encode() => /* ... */;
}
The annotations are designed to be compatible with virtually any serialization package like json_serializable
or dart_mappable
. Simply annotate the methods generated by these packages either directly, or by using a wrapper method.
While Map<String, dynamic>
is the most common type for serializing dart classes, you can also use other primitive types
like String
, List<dynamic>
etc. as long as the encoding method returns the same type as the decoding method accepts.
Customize serialization of third-party types
Sometimes, you cannot control the methods of a class, such as when using a third-party library. In these cases, you can create a custom override type which "redefines" the type for serialization.
For example, consider the case where the Model
class is imported from a third-party library, package:model
.
Since we do not own package:model
, we cannot change the methods of the Model
class.
Instead of modifying the Model
class, we can define a custom override for Model
which will be used in place of the
original Model
class when it's used for serialization in Jaspr.
import 'package:jaspr/jaspr.dart';
import 'package:model/model.dart';
// We create an extension type which wraps over the third-party type and
// defines the @decoder and @encoder methods
//
// Since the extension type implements the original type, it will behave
// identically to the original except for the serialization logic.
extension type ModelOverride(Model model) implements Model {
@decoder
factory ModelOverride.decode(Map<String, dynamic> data) {
return ModelOverride(
Model(
// decode the values of [data]
/* ... */
),
);
}
@encoder
Map<String, dynamic> encode() => {
// encode the values of [model]
/* ... */
};
}
Custom overrides are defined as extension types which wrap and implement the original type. You must always implement the original type in your extension type.