@@ -40,8 +40,8 @@ abstract class SerializationHook implements StructureMetadata {
4040 /// - `map` : The map representation of the object to be deserialized.
4141 /// - `structure` : The `DogStructure` instance associated with the object to be deserialized.
4242 /// - `engine` : The `DogEngine` instance that will perform the deserialization.
43- void beforeDeserialization (Map < String , dynamic > map, DogStructure structure,
44- DogEngine engine) {}
43+ void beforeDeserialization (
44+ Map < String , dynamic > map, DogStructure structure, DogEngine engine) {}
4545}
4646
4747/// `FieldSerializationHook` is a mixin for field structure metadata
@@ -50,12 +50,19 @@ abstract class SerializationHook implements StructureMetadata {
5050///
5151/// This interface is used by [NativeSerializerMode] and descendants.
5252mixin FieldSerializationHook on StructureMetadata {
53-
5453 /// This method is called after a field is serialized by [NativeSerializerMode] .
55- void postFieldSerialization (NativeStructureContext context, NativeStructureFieldContext fieldContext, Map <String , dynamic > map, DogEngine engine) {}
54+ void postFieldSerialization (
55+ NativeStructureContext context,
56+ NativeStructureFieldContext fieldContext,
57+ Map <String , dynamic > map,
58+ DogEngine engine) {}
5659
5760 /// This method is called before a field is deserialized by [NativeSerializerMode] .
58- void beforeFieldDeserialization (NativeStructureContext context, NativeStructureFieldContext fieldContext, Map <String , dynamic > map, DogEngine engine) {}
61+ void beforeFieldDeserialization (
62+ NativeStructureContext context,
63+ NativeStructureFieldContext fieldContext,
64+ Map <String , dynamic > map,
65+ DogEngine engine) {}
5966}
6067
6168/// A function that may be used to transform a map before deserialization.
@@ -79,8 +86,8 @@ class LightweightMigration extends SerializationHook {
7986
8087 /// Executes each migration function in the `migrations` list before deserialization.
8188 @override
82- void beforeDeserialization (Map < String , dynamic > map, DogStructure structure,
83- DogEngine engine) {
89+ void beforeDeserialization (
90+ Map < String , dynamic > map, DogStructure structure, DogEngine engine) {
8491 for (var value in migrations) {
8592 value (map, structure, engine);
8693 }
@@ -112,8 +119,8 @@ class RevisionMigration extends SerializationHook {
112119 /// Executes each migration function in the `migrations` list that corresponds to
113120 /// a version number greater than or equal to the current version.
114121 @override
115- void beforeDeserialization (Map < String , dynamic > map, DogStructure structure,
116- DogEngine engine) {
122+ void beforeDeserialization (
123+ Map < String , dynamic > map, DogStructure structure, DogEngine engine) {
117124 final version = map[revisionKey] as int ? ?? 0 ;
118125 for (var i = version; i < migrations.length; i++ ) {
119126 if (i >= version) {
@@ -146,26 +153,64 @@ class DefaultValue extends StructureMetadata with FieldSerializationHook {
146153 /// otherwise it will be removed if the field is equal to the default value.
147154 const DefaultValue (this .value, {this .keep = false });
148155
149- dynamic _getNativeDefault (NativeStructureFieldContext fieldContext, DogEngine engine) {
156+ dynamic _getNativeDefault (
157+ NativeStructureFieldContext fieldContext, DogEngine engine) {
150158 final provided = value is DefaultValueSupplier ? value () : value;
151159 final native = fieldContext.encodeValue (provided, engine);
152160 return native ;
153161 }
154162
155163 @override
156- void beforeFieldDeserialization (NativeStructureContext context, NativeStructureFieldContext fieldContext, Map <String , dynamic > map, DogEngine engine) {
164+ void beforeFieldDeserialization (
165+ NativeStructureContext context,
166+ NativeStructureFieldContext fieldContext,
167+ Map <String , dynamic > map,
168+ DogEngine engine) {
157169 if (! map.containsKey (fieldContext.key)) {
158170 map[fieldContext.key] = _getNativeDefault (fieldContext, engine);
159171 }
160172 }
161173
162174 @override
163- void postFieldSerialization (NativeStructureContext context, NativeStructureFieldContext fieldContext, Map <String , dynamic > map, DogEngine engine) {
175+ void postFieldSerialization (
176+ NativeStructureContext context,
177+ NativeStructureFieldContext fieldContext,
178+ Map <String , dynamic > map,
179+ DogEngine engine) {
164180 if (! keep) {
165181 final nativeValue = _getNativeDefault (fieldContext, engine);
166182 if (deepEquality.equals (map[fieldContext.key], nativeValue)) {
167183 map.remove (fieldContext.key);
168184 }
169185 }
170186 }
171- }
187+ }
188+
189+ /// A **field** and **class** level serialization hook that excludes fields
190+ /// with a `null` value from the serialized map.
191+ const ExcludeNull excludeNull = ExcludeNull ();
192+
193+ /// A **field** and **class** level serialization hook that excludes fields
194+ /// with a `null` value from the serialized map.
195+ class ExcludeNull extends SerializationHook with FieldSerializationHook {
196+ const ExcludeNull ();
197+
198+ @override
199+ void postFieldSerialization (
200+ NativeStructureContext context,
201+ NativeStructureFieldContext fieldContext,
202+ Map <String , dynamic > map,
203+ DogEngine engine) {
204+ // Remove the field if its value is null
205+ if (map[fieldContext.key] == null ) {
206+ map.remove (fieldContext.key);
207+ }
208+ }
209+
210+ @override
211+ void postSerialization (dynamic obj, Map <String , dynamic > map,
212+ DogStructure structure, DogEngine engine) {
213+ // Remove all null values from the map
214+ map.removeWhere ((key, value) => value == null );
215+ }
216+ }
0 commit comments