5. Polymorphism
DOGs supports polymorphism on a per-field basis. This means that you can have a field with any type
you want, as long as all leaf types are serializable. If you want to use polymorphism, you need to
add the @polymorphic
annotation - This is required so you don't accidentally use polymorphism
without knowing it.
Abstract classes and interfaces mustn't be annotated with @serializable
You only need to annotate concrete leaf classes with @serializable
. Abstract classes and interfaces
can't be instantiated and therefore can't use automatic structure generation, for which
@serializable
is the marker. (This excludes interop for built_value)
Therefore: Only annotate concrete types with @serializable
.
You may specify custom converters for abstract classes and interfaces though, if you want to use them as explicit types. In this case, they will not be handled as polymorphic.
Limitations
All leaf types must be serializable. This means that you can use dynamic
or Object
as long as
the actual runtime type is serializable i.E. the runtime type is associated with a structure definition
and has a converter.
Discriminator
To identity a leaf type in a polymorphic field, DOGs uses a _type
discriminator, that is added
to the serialized data of the object in question. If the leaf object is not a map, tha value will
be wrapped in a map and stored in the _value
field.
When do I need to use @polymorphic?
If all leaf node of your fields type tree are concrete classes, or have an associated structure
and converter, you don't need to use @polymorphic
.
Type | Polymorphic? | Explanation |
---|---|---|
int |
int is a serializable class and therefore does not need to be annotated. |
|
List<int> |
int is a serializable class and therefore does not need to be annotated. |
|
List<Animal> |
Animal is an abstract class and therefore needs to be annotated. |
|
List<Object> |
Object is an abstract class and therefore needs to be annotated. |
|
Map<String,String> |
All leaf types are serializable classes therefore no annotation is required. | |
Map<String,Animal> |
Animal is an abstract class and therefore needs to be annotated. |
|
Map<String,Object> |
Object is an abstract class and therefore needs to be annotated. |
|
Map<String,Person> |
Person is a serializable class and therefore does not need to be annotated. |
|
Map<String, List<String>> |
All leaf types are serializable classes therefore no annotation is required. |
Examples
sealed class Animal {}
@serializable
class Dog extends Animal {
String name;
int age;
Dog(this.name, this.age);
}
@serializable
class Dolphin extends Animal {
bool isNamedFlipper;
Dolphin(this.isNamedFlipper);
}
@serializable
class Zoo {
@polymorphic
List<Animal> animals;
Zoo(this.animals);
}