Reputation: 6766
I want to set a default value for AvailableService
. It straight forward enough with primitives. How would I do it with a custom Object
class Submenu extends Equatable {
@JsonKey(defaultValue: "")
final String name;
@JsonKey(defaultValue: new AvailableService(false,false,false,false))
final AvailableService availableService;
}
the custom Object:
AvailableService {
bool supportsDelivery;
bool supportsTableService;
bool supportsCollection;
bool supportsChat;
}
And the compile time error is
Arguments of a constant creation must be constant expressions.
Try making the argument a valid constant, or use 'new' to call the constructor
Upvotes: 7
Views: 10781
Reputation: 1673
For those who want to use constants to manage source code more optimally.
Because the json_serializable
handler will try to call a "constant" function when passing a label to defaultValue
if it is not "literal".
So what you need to do is create a static function that returns the default value:
@JsonSerializable(explicitToJson: true)
class MetadataDto {
@JsonKey(name: "version_name")
final String versionName;
@JsonKey(name: "version_code")
final int versionCode;
const MetadataDto({
this.versionName = "1.0.0",
this.versionCode = 1,
});
static MetadataDto kDefault() => const MetadataDto();
}
In another instance, set the singleton function as defaultValue
as it name (without parentheses).
@JsonSerializable(explicitToJson: true)
class ContentDto {
@JsonKey(name: "metadata", defaultValue: MetadataDto.kDefault)
final MetadataDto info;
const ContentDto({
required this.info,
});
}
Check the .g.dart
(generated file) after run build_runner
:
ContentDto _$ContentDto FromJson(Map<String, dynamic> json) =>
ContentDto(
info: json['metadata'] == null
? MetadataDto.kDefault()
: MetadataDto.fromJson(json['metadata'] as Map<String, dynamic>),
);
That'is it.
Upvotes: 1
Reputation: 5876
Starting from json_serializable 5, generated fromJson uses default parameters from constructor, so you can do this
@JsonSerializable()
class Cart {
final List<int> items;
const Cart({
this.items = const [],
});
factory Cart.fromJson(Map<String, dynamic> json) => _$CartFromJson(json);
Map<String, dynamic> toJson() => _$CartToJson(this);
}
@JsonSerializable()
class User {
final Cart cart;
const User({
this.cart = const Cart(),
});
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
}
Then Cart.fromJson({}).items
or User.fromJson({}).cart.items
will give you []
Upvotes: 6
Reputation: 1988
In general, as an annotation argument you can only pass constants, so you cannot pass an object created with new but only with a const constructor (you should define all AvailableService fields as final, and define a const constructor). In json_Serializable, however, defaultValue currently has some additional constraints:
@JsonKey(defaultValue: {"supportsDelivery" : false, "supportsTableService" : false, /* etc */})
), but even this possibility is currently only usable for the default value of fields with Map type, and not for fields with custom types (like AvailableService). In this case, you not get an error, but the defaultValue will never be used (by looking at the code generated in the .g.dart file, you can understand why). There are open requests for this issue as well: #676 - Allow default value encoded as JSON and #789 - how to set default value to nested JSON objects?At the moment, therefore, until the aforementioned requests are followed up, the only workaround I have found is handle the defaultValue in the fromJson()
factory:
factory AvailableService.fromJson(Map<String, dynamic> json) =>
json != null
? _$AvailableServiceFromJson(json)
: AvailableService(false, false, false, false);
In short, JsonKey.defaultValue
currently only supports literals -not even accepting constants- and can only be used for the default value of primitive type fields (or List, Map, Set).
Upvotes: 11