'How to set a default value for an object in json serialisable?

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


Solution 1:[1]

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:

  • You can't even use a custom object created with a const constructor (or you get the error "it must be a literal"). There is an open request to remove this constraint: #741 - Const as default value
  • As defaultValue only literals are allowed; you could then pass a Map literal (ie: @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).

Solution 2:[2]

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 []

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Mabsten
Solution 2 Pavel