Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatically call .toJson() of children objects in _$<NameOfObject>ToJson(<Object>) #561

Closed
nicholaschiang opened this issue Nov 16, 2019 · 3 comments

Comments

@nicholaschiang
Copy link

Why doesn't the json_serializable package automatically call toJson() for child objects?

For example, in message.dart, I've got:

import 'package:json_annotation/json_annotation.dart';
import 'package:meta/meta.dart';

import 'user.dart';

part 'message.g.dart';

@JsonSerializable()
class Message {
  const Message({
    @required this.id,
    @required this.text,
    @required this.sentBy,
    @required this.timestamp,
  })  : assert(id != null),
        assert(text != null),
        assert(sentBy != null),
        assert(timestamp != null);

  final String id;
  final String text;
  final User sentBy;
  final DateTime timestamp;

  @override
  String toString() => "Message from ${sentBy.name} ($id)";

  factory Message.fromJson(Map<String, dynamic> json) =>
      _$MessageFromJson(json);

  Map<String, dynamic> toJson() => _$MessageToJson(this);
}

And that User object is also @JsonSerializable() as seen in user.dart:

import 'package:json_annotation/json_annotation.dart';
import 'package:meta/meta.dart';

part 'user.g.dart';

@JsonSerializable()
class User {
  final String id;
  final String name;
  final String username;
  final String photo;
  bool active;

  User({
    @required this.id,
    @required this.name,
    @required this.photo,
    @required this.username,
    @required this.active,
  })  : assert(id != null),
        assert(name != null),
        assert(photo != null),
        assert(username != null),
        assert(active != null);

  String get firstName => name.split(' ')[0];
  String get lastName => name.split(' ')[name.split(' ').length - 1];

  @override
  String toString() => "$name a.k.a. $username ($id)";

  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);

  Map<String, dynamic> toJson() => _$UserToJson(this);
}

Except that the generated message.g.dart (by running $ flutter pub run build_runner build) doesn't automatically call that toJson() method (which to me seems strange):

Map<String, dynamic> _$MessageToJson(Message instance) => <String, dynamic>{
      'id': instance.id,
      'text': instance.text,
      'sentBy': instance.sentBy,
      'timestamp': instance.timestamp?.toIso8601String()
    };

Any suggestions (besides manually editing the _$MessageToJson method)?

@nicholaschiang
Copy link
Author

Current workaround is just to manually edit message.g.dart to look like this:

Map<String, dynamic> _$MessageToJson(Message instance) => <String, dynamic>{
      'id': instance.id,
      'text': instance.text,
      'sentBy': instance.sentBy.toJson(),
      'timestamp': instance.timestamp?.toIso8601String()
    };

Not the best solution, but it works for now.

@kevmoo
Copy link
Collaborator

kevmoo commented Nov 16, 2019

This is by design. The JSON encoding logic in dart:convert calls toJson for you, which means calls to toJson are lazy.

You can override this by using https://pub.dev/documentation/json_annotation/latest/json_annotation/JsonSerializable/explicitToJson.html

@masus04
Copy link

masus04 commented Sep 12, 2023

Calling toJson on JsonSerializable types automatically would simplify use a lot 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants