Freezed: toJson/fromJson is broken for nested lists of freezed objects

Created on 15 Jul 2020  路  2Comments  路  Source: rrousselGit/freezed

Consider the following example:

import 'package:freezed_annotation/freezed_annotation.dart';

part 'main.freezed.dart';
part 'main.g.dart';

@freezed
abstract class TodoList with _$TodoList {
  factory TodoList(List<Todo> todos) = _TodoList;
  factory TodoList.fromJson(Map<String, dynamic> json) => _$TodoListFromJson(json);
}

@freezed
abstract class Todo with _$Todo {
  factory Todo(String name, bool checked) = _Todo;
  factory Todo.fromJson(Map<String, dynamic> json) => _$TodoFromJson(json);
}

Observe the following test fail:

import 'package:flutter_test/flutter_test.dart';

import 'package:freezed_json_bug/freezed_json_bug.dart';
import 'package:collection/collection.dart';

void main() {
  test('serialize deserialize', () {
    final todos = <Todo>[
      Todo("Item 1", true),
      Todo("Item 2", false),
    ];

    final todoList = TodoList(todos);

    final todoListJson = todoList.toJson();

    final todoListReserialized = TodoList.fromJson(todoListJson);

    Function deepEq = const DeepCollectionEquality().equals;

    expect(deepEq(todoList.toJson(), todoListReserialized.toJson()), true);
  });
}

with the following stacktrace:

type '_$_Todo' is not a subtype of type 'Map<String, dynamic>' in type cast
package:freezed_json_bug/src/main.g.dart 13:55        _$_$_TodoListFromJson.<fn>
dart:_internal                                        ListIterable.toList
package:freezed_json_bug/src/main.g.dart 14:11        _$_$_TodoListFromJson
package:freezed_json_bug/src/main.freezed.dart 89:7   new _$_TodoList.fromJson
package:freezed_json_bug/src/main.freezed.dart 12:20  _$TodoListFromJson
package:freezed_json_bug/src/main.dart 9:59           new TodoList.fromJson
test/freezed_json_bug_test.dart 17:43                 main.<fn>

This is because in main.g.dart we have:

Map<String, dynamic> _$_$_TodoListToJson(_$_TodoList instance) =>
    <String, dynamic>{
      'todos': instance.todos,
    };

rather than:

Map<String, dynamic> _$_$_TodoListToJson(_$_TodoList instance) =>
    <String, dynamic>{
      'todos': instance.todos.map((e) => e.toJson()).toList(),
    };

Most helpful comment

Thanks for the quick explainer, adding that annotation fixed the test:

@freezed
abstract class Todo with _$Todo {
  // must be above factory method
  @JsonSerializable(explicitToJson: true)
  factory Todo(String name, bool checked) = _Todo;
  factory Todo.fromJson(Map<String, dynamic> json) => _$TodoFromJson(json);
}

Optionally creating build.yaml mentioned in https://github.com/rrousselGit/freezed/issues/86 (only stumbled upon this now 馃槄 ) is a fix too:

targets:
  $default:
    builders:
      json_serializable:
        options:
          explicit_to_json: true

Out of these two I think of going for build.yaml fix and making this explicitToJson true by default everywhere. It's less code to write and less things to worry about.

All 2 comments

This is the "expected" behavior of json_serializable

You are supposed to either specify a @JsonSerializable(explicitToJson: true) or change explicitToJson inside your build.yaml file. https://github.com/google/json_serializable.dart/tree/master/json_serializable#build-configuration

Thanks for the quick explainer, adding that annotation fixed the test:

@freezed
abstract class Todo with _$Todo {
  // must be above factory method
  @JsonSerializable(explicitToJson: true)
  factory Todo(String name, bool checked) = _Todo;
  factory Todo.fromJson(Map<String, dynamic> json) => _$TodoFromJson(json);
}

Optionally creating build.yaml mentioned in https://github.com/rrousselGit/freezed/issues/86 (only stumbled upon this now 馃槄 ) is a fix too:

targets:
  $default:
    builders:
      json_serializable:
        options:
          explicit_to_json: true

Out of these two I think of going for build.yaml fix and making this explicitToJson true by default everywhere. It's less code to write and less things to worry about.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

matiasosuna picture matiasosuna  路  4Comments

rakakhrl picture rakakhrl  路  6Comments

alfinbi picture alfinbi  路  4Comments

pblinux picture pblinux  路  4Comments

narcodico picture narcodico  路  6Comments