29

I want to add a custom converter to a freezed class like in this answer.

I tried it with this code:

@freezed
class NewsPost with _$NewsPost {
  factory NewsPost({
    @JsonKey(name: "date") @TimestampConverter() DateTime? date,
  }) = _NewsPost;

  factory NewsPost.fromJson(Map<String, dynamic> json) =>
      _$NewsPostFromJson(json);
}

But it did not work. Any ideas are more than welcome!

For your interest, this is my Converter:

class TimestampConverter implements JsonConverter<DateTime, Timestamp> {
  const TimestampConverter();

  @override
  DateTime fromJson(Timestamp timestamp) {
    return timestamp.toDate();
  }

  @override
  Timestamp toJson(DateTime date) => Timestamp.fromDate(date);
}

Thank you :-)

Valentin Seehausen
  • 665
  • 1
  • 8
  • 10
  • Can you expand on "did not work"? Your code is correct. – Alex Hartford Apr 20 '21 at 16:53
  • 2
    @valentin-seehausen please see more reply on the issue you commented on in the freezed repo: https://github.com/rrousselGit/freezed/issues/15#issuecomment-828182464 – Maks Apr 28 '21 at 06:39

2 Answers2

30

Since null safety was introduced, for JsonConverter to work with the freezed generator the nullability of the types declared in JsonConverter need to match the nullability of the type in the freezed class.

If the types do not match, freezed ignores the converter.

So using your example:

@freezed
class NewsPost with _$NewsPost {
  factory NewsPost({
    @TimestampOrNullConverter() DateTime? date, // <-- this is nullable, so the converter needs to handle null
    @TimestampConverter() DateTime createdAt, // <-- not nullable, so your exsiting converter will work
  }) = _NewsPost;

  factory NewsPost.fromJson(Map<String, dynamic> json) =>
      _$NewsPostFromJson(json);
}

class TimestampConverter implements JsonConverter<DateTime, Timestamp> {
  const TimestampConverter();

  @override
  DateTime fromJson(Timestamp timestamp) {
    return timestamp.toDate();
  }

  @override
  Timestamp toJson(DateTime date) => Timestamp.fromDate(date);
}

class TimestampOrNullConverter implements JsonConverter<DateTime?, Timestamp?> {
  const TimestampOrNullConverter();

  @override
  DateTime? fromJson(Timestamp? timestamp) {
    return timestamp?.toDate();
  }

  @override
  Timestamp? toJson(DateTime? date) => date == null ? null : Timestamp.fromDate(date);
}

Tested and working on flutter 2.5.3 with the following dependency versions:

dev_dependencies:
  build_runner: ^2.1.4
  freezed: ^0.15.0+1
  json_serializable: ^5.0.2
Benjamin
  • 8,128
  • 3
  • 34
  • 45
Bulwinkel
  • 2,111
  • 25
  • 23
12

Well, it´s not the most elegant solution, but it works.

@freezed
class NewsPost with _$NewsPost {
  factory NewsPost({
    @JsonKey(
       name: "date", 
       fromJson: dateTimeFromJson, 
       toJson: dateTimeToJson,
    ) DateTime? date,
  }) = _NewsPost;

  factory NewsPost.fromJson(Map<String, dynamic> json) =>
      _$NewsPostFromJson(json);
}


DateTime dateTimeFromJson(Timestamp timestamp) {
    return timestamp.toDate();
}

Timestamp dateTimeToJson(DateTime date) => Timestamp.fromDate(date);

I think it´s a solution. Using JsonConverter I can't get it to work.

Neifen
  • 2,546
  • 3
  • 19
  • 31