json_serializable.dart
json_serializable.dart copied to clipboard
include_if_null to exclude non-nullable fields whose toJson() can return null
A use case is when using constructs such as Optional
or Option
.
For example:
import 'package:json_annotation/json_annotation.dart';
part 'example.g.dart';
@JsonSerializable(includeIfNull: false)
class Person {
final String firstName;
@JsonKey(includeIfNull: false)
final Option<String> maybeLastName;
Person({required this.firstName, required this.maybeLastName});
factory Person.fromJson(Map<String, dynamic> json) => _$PersonFromJson(json);
Map<String, dynamic> toJson() => _$PersonToJson(this);
}
Running
Person(firstName: "John", maybeLastName: None()).toJson()
will return
{"name": "John", "maybeLastName": null}
which is not what I expect. I expect "maybeLastName" to be excluded from the json given that it's null. Expected output:
{"name": "John"}
option.toJson()
returns null
if it's a None
and T
if it's a Some()
.
The specific Option
implementation I'm using is from fpdart
+1 This is a problem for me too.
I am experiencing a similar issue.
In my case, I have an enum with a null
json value (to avoid a nullable type within my model class)
@JsonEnum()
enum FoodType {
@JsonValue(1)
restaurant,
@JsonValue(2)
grocery,
@JsonValue(null)
unknown,
}
My Dart model class property:
@JsonKey(includeIfNull: false)
final FoodType brandedType;
This is the generated code for this property
'branded_type': _$FoodTypeEnumMap[instance.brandedType]!,
...
const _$FoodTypeEnumMap = {
FoodType.restaurant: 1,
FoodType.grocery: 2,
FoodType.unknown: null,
};
What's happening in the generator is it's checking for a nullable type on the model class's property type. If the property is not a nullable type (as a Dart object), then it would seem redundant to generate the writeNotNull
method because the value appears to not be nullable (as a serialized object).
This can be validated by making the property's type nullable
// --- model ---
@JsonKey(includeIfNull: false)
final FoodType? brandedType;
// --- generated code ---
void writeNotNull(String key, dynamic value) {
if (value != null) {
val[key] = value;
}
}
writeNotNull('branded_type', _$FoodTypeEnumMap[instance.brandedType]);
...
const _$FoodTypeEnumMap = {
FoodType.restaurant: 1,
FoodType.grocery: 2,
FoodType.unknown: null,
};
This is the similar situation that @andcea is experiencing, but instead of _$EnumMap[...]
(where the key's value could return a null
value), it would be property.toJson()
(where toJson
could return a null
value). Since we are checking for the null value against the serialized property, and not the Dart model object's current value, the property's type isn't relevant.
The fix for this would be to ignore the nullable typing on the property of the Dart object, and generate the writeNotNull
regardless.
@andcea – I use Dart's notion of nullability. I cannot support an arbitrary Option
type like you have. The solution would be to use
@JsonKey(includeIfNull: false)
final String? maybeLastName;
@mrgnhnt96 – please file a separate issue for your problem!
@kevmoo this issue wasn't about supporting Option
, that was just an example.
The request is for @JsonKey(includeIfNull: false)
to support use cases where the type is non-nullable but toJson()
can return null
.
Right now if toJson()
returns null
on a field that has includeIfNull: false
, it will still be included in the output.
Please re-open this issue as it wasn't completed and I think it's a valid feature request.
Understood. It's a bit of a weird case, honestly. Will need to ponder.
Any news on that topic? I also have this use case. I have a list of objects, some are auto generated so I don't want to serialize them.
They have a certain value, so it would be great If I just could return null within the toJson Method to exclude them.
If I can offer my two cents, I'm running into this same issue and have been trying to debug the situation:
I've made my own class that works like an enum with an internal value, and I'm trying to serialize the value, or exclude it if the property in the structure is null
. This is going through a custom toJson
method that extracts the string equivalent of the internal value of the "enum":
Through a few levels of inheritence, it comes down to this line here:
Which, oddly enough is resulting in the word "null", which is different than null
, which fails the writeNotNull
check in the auto-generated g file.
Solution? Instead of accidentally turn null
into the string "null", I missed a null-check:
Just passing along my experience, in case it helps anyone else.