1. Serializable Classes
To create a serializable class, just annotate it with @serializable
and mixin
Dataclass<T>
. The code generator will then generate the required structure definition of
your class.
Explore Code Snippets
You can explore the code in codeblocks by expanding comments using the floating (+) button.
@serializable /*(1)!*/
class Person with Dataclass<Person> /*(2)!*/ {
final String name;
final int age;
final Set<String>? tags; /*(3)!*/
Person(this.name, this.age, this.tags); /*(4)!*/
}
@serialzable // (5)!
enum MyEnum {
a,b,c;
}
- The serializable annotation is required to make a class serializable.
- The dataclass mixin is optional but recommended, as it provides equals, hashCode and toString implementations.
- DOGs natively supports
List<T>
andSet<T>
for any serializable type. While the field itself is allowed to be null, the elements of the iterable must not be null. If you require nested nullability, consider using theOptional<T>
type. - You constructor must only reference serializable field and must not be private.
You can also use a secondary constructor for serialization by naming it
dogs
. Non-formal fields can also be used if they have a backing getter of field with the same name. - You can also annotate enums to make them serializable. Enum values will be serialized and deserialized as strings using their name.
Conformities
Not every serializable class must be semantically equal to this dataclass example. Besides the initially presented dataclass, DOGs also supports the following other conformities:
@serializable
class Person with Dataclass<Person> {
final String name;
final int age;
final Set<String>? tags;
Person(this.name, this.age, this.tags);
}
Dataclasses are the most common type of serializable classes. They are immutable and their fields should be final. They are also the only type of serializable class you should use when you require equality.
Named Argument Constructors
You can also use named arguments with you dataclass constructor. This is especially useful when you have a lot of optional fields or many fields with the same type.
@serializable
class Person {
String name;
int age;
Set<String>? tags;
Person(this.name, this.age, this.tags);
}
If you don't use the dataclass mixin, the generator will not generate equality and hashcode implementations for this structure and you will have to implement them yourself if required. Since the generator doesn't expect this class to be immutable, you can use mutable fields and setters with this type of serializable class.
Prefer other conformities like Dataclass!
@serializable
class Person {
late String name;
int? age;
Set<String>? tags;
@beanIgnore
late String ignored;
}
Beans are the most flexible but also the most error prone type of serializable class. Serializable fields must be mutable and have a public no-arg constructor. They are only intended for frameworks which benefit from such a structure for simplicity.
To instantiate a bean, you should use the generated {name}Factory
class with its
static create
method.
Field Variants
To not limit your creativity, DOGs supports multiple ways to define serializable fields. This includes (super) formal parameters, which refer to fields and non-formal parameters which have a backing field or getter with the same name. This list showcases all possible variants:
@serializable
class Entity extends Base with Dataclass<Person> {
final String name;
Entity({
required super.id,
required this.name
});
}
The super field can have annotations
The super parameter must have a formal base definition
The super parameter must end up as a formal parameter in the superclasses constructor. Recursive backing fields or getters are not allowed in this case.
Default Values
You can set default values for fields, which will be considered when deserializing and serializing the value of the field.
This will set the default value of the field to "Alex". If the field is not present in the serialized data, the default value will be used. If the field is present, the default value will be ignored. When the object is serialized, the serializer will check if the value is equal to the default value and will omit the field if it is.
Including the default value
If you want to include the field even if it is equal to the default
value, you can set the keep
parameter to true
.
Restrictions
To make your serializable classes work with the serialization system, you must follow a few restrictions (to read more about the restrictions, expand the region below).
No Class-Level Generics
You cannot use generics on the class level. This is due to the fact that the generator
generates a structure definition for your class, which erases all generic information which
is not used in the fields of your class.
Generics on fields are allowed, though!
Don't use Records
You cannot use records as field types. This is due to the fact that records can't be easily represented by the structure format and make the overall system more unnecessarily complex and possible generated model schemas obscure.
Types inside Field-Generics can't be nullable
You cannot use generic field types with nullable type arguments, as the type tree does not
store the nullability of the type arguments. If you require nullable items, consider using
the Optional<T>
type instead, which is a wrapper for nullable types.
In practice, this means that you can't use List<String?>
but you can use List<Optional<String>>
.
The root type of the field can be nullable!
List<String>?
is perfectly fine without any changes.
All leaf types must be serializable
All fields of your serializable class must be serializable recursively themselves.
For sealed classes for example, this means that all possible subclasses must be serializable.
This also means, that they need to be marked as @serializable
if they don't have a custom
converter registered.
See Polymorphism for more information.
Parameters must either be formal or have a backing member with the same name
All parameters of your constructor must either be formal parameters (this./super.) or have a backing member with the same name. This class member can either be a field or a getter.
Terminology: Leaf Type
Objects which are possible terminal values of a type boundary are referred to as leaf types.
In practice, this refers to the runtimeType
of the object in question.
If you have a field of type Animal
, Animal
is the type boundary and possible leaf types
would be Dog
or Cat
. For DOGs, this would mean Dog
and Cat
need to be serializable.
Modifications
You can use the automatically generated builder to modify serializable classes easily. Depending on your prefer code style, you can use either the imperative or lambda builder.
Availability
The builder is only available for dataclasses and basic serializable classes.