👋
Given two freezed classes where one is "nested" in the other.
import 'package:freezed_annotation/freezed_annotation.dart';
part 'contrived_example.g.dart';
part 'contrived_example.freezed.dart';
@freezed
abstract class TopLevel with _$TopLevel {
const factory TopLevel(
String niceString,
Nested doesNotSerializeButDoesDeserialize,
) = _TopLevel;
factory TopLevel.fromJson(Map<String, dynamic> json) =>
_$TopLevelFromJson(json);
}
@freezed
abstract class Nested with _$Nested {
const factory Nested(int niceInteger) = _Nested;
factory Nested.fromJson(Map<String, dynamic> json) => _$NestedFromJson(json);
}
The generated code for json_serializable doesn't serialize the nested object. DEserialization works as expected.
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'contrived_example.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$_TopLevel _$_$_TopLevelFromJson(Map<String, dynamic> json) {
return _$_TopLevel(
json['niceString'] as String,
json['doesNotSerializeButDoesDeserialize'] == null
? null
: Nested.fromJson(
json['doesNotSerializeButDoesDeserialize'] as Map<String, dynamic>),
);
}
Map<String, dynamic> _$_$_TopLevelToJson(_$_TopLevel instance) =>
<String, dynamic>{
'niceString': instance.niceString,
// 👇 should have toJson() or map((element) => element.toJson()) for Lists
'doesNotSerializeButDoesDeserialize':
instance.doesNotSerializeButDoesDeserialize,
};
_$_Nested _$_$_NestedFromJson(Map<String, dynamic> json) {
return _$_Nested(
json['niceInteger'] as int,
);
}
Map<String, dynamic> _$_$_NestedToJson(_$_Nested instance) => <String, dynamic>{
'niceInteger': instance.niceInteger,
};
At first, I thought that it's an issue with json_serializable but if that library is used by itself, it serializes nested objects marked with @JsonSerializable just fine.
I have a very deeply nested object and it works fine for me.
The generated code you gave is generated by json_serializable, so I have no control over it.
Is freezed correctly adding @JsonSerializable annotation on Nested?
If it does, then it's unlikely to be a bug with freezed
The _$_Nested is annotated.
@JsonSerializable()
class _$_Nested implements _Nested {...}
Then it may be an issue with build_runner.
Try regenerating the sources (potentially deleting .dart_tool) and see if it works.
In any case, freezed does nothing besides adding this annotation. So if it's there, then I can't do anything 🙃
Whoops! Sorry to break it to you, Rémi, but the bug is _probably_ on your side 😅
I replicated the non-serializing behavior with regular classes too. All it took for the nested class to serialize was @JsonSerializable(explicitToJson: true) on the top-level class.
I mean it depends on what encoder you use.
The documentation of explicitToJson explicitly says that it's not needed using dart:convert.
If you need it, it's your job to add it or your encoder's job
OK, pardon me 🤦♂️ I'll leave the build.yaml set up here for any time travelers from the future.
targets:
$default:
builders:
json_serializable:
options:
explicit_to_json: true
Thank you!
thanks, resoDev and Remi, I am from the future and this conversation helped me
Works great!
But I was wondering if we can set explicitToJson to true for specific fields, and false for other fields.
I tried annotating each field but that didn't seem to work
Here's my use case:
@freezed
abstract class SearchFilters with _$SearchFilters {
const factory SearchFilters({
List<CategoryEnum> category,
CustomClass customClass,
}) = _SearchFilters;
factory SearchFilters.fromJson(Map<String, dynamic> json) =>
_$SearchFiltersFromJson(json);
}
I want customClass to be explicit to json, but the category to not be explicit to Json. Here's my CategoryEnum class:
@freezed
abstract class CategoryEnum implements _$CategoryEnum {
const CategoryEnum._();
const factory CategoryEnum(String label) = _CategoryEnum;
static const category1 = CategoryEnum("Category 1");
static const category2 = CategoryEnum("Category 2");
factory CategoryEnum.fromJson(String val) {
return CategoryEnum(val);
}
@override
String toString() => this.label;
}
I don't think you can, no
Thanks for the quick response. I was able to fix this by setting explicitToJson to true, and using @JsonKey(toJson: CategoryEnum.serializeToList) to define a custom toJson function for my enum class
@freezed
abstract class CategoryEnum implements _$CategoryEnum {
const CategoryEnum._();
const factory CategoryEnum(String label) = _CategoryEnum;
static const category1 = CategoryEnum("1");
static const category2 = CategoryEnum("2");
factory CategoryEnum.fromJson(String val) {
return CategoryEnum(val);
}
static List<String> serializeToList(List<CategoryEnum> e) {
return e.map((a) => a.toString()).toList();
}
@override
String toString() => this.label;
}
Most helpful comment
OK, pardon me 🤦♂️ I'll leave the
build.yamlset up here for any time travelers from the future.Thank you!