google / tuple.dart

A library providing a tuple data structure
https://pub.dev/packages/tuple
BSD 2-Clause "Simplified" License
195 stars 26 forks source link

Compatibility with json_serializable #19

Open realcr opened 4 years ago

realcr commented 4 years ago

Hi, thank you for your work on tuple! Is there a recommended way to use tuple together with json_serializable?

For example, if I want to automatically serialize a class that looks like this:

@JsonSerializable(nullable: false)
class Person {
  final String firstName;
  final String lastName;
  final Tuple2<String,int> myTuple;

  Person({this.firstName, this.lastName, this.myTuple});

  factory Person.fromJson(Map<String, dynamic> json) => _$PersonFromJson(json);
  Map<String, dynamic> toJson() => _$PersonToJson(this);
}
rhalff commented 4 years ago

You could use a converter to serialize tuples.

The below is a bit convoluted where I also extend Tuple, but similar should be possible by creating a TupleConverter to operate on a tuple directly.

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

class Entry extends Tuple2<String, double> {
  const Entry(item1, item2) : super(item1, item2);

  String get label => this.item1;
  double get amount => this.item2;
}

class EntryConverter implements JsonConverter<Entry, List<dynamic>> {
  static const instance = EntryConverter();

  const EntryConverter();

  @override
  Entry fromJson(dynamic json) {
    final label = json[0];
    final amount = json[1] == null ? 0.0 : double.parse(json[1]);

    return Entry(label, amount);
  }

  @override
  List<dynamic> toJson(Entry entry) {
    return entry == null ? null : [entry.label, entry.amount];
  }
}

@JsonSerializable()
@EntryConverter.instance
class Details {
  List<Entry> entries;
}

Access to .instance is just an optimization, I based this version on the TrivialNumberConverter in the tests.

realcr commented 4 years ago

@rhalff : Thanks for the detailed reply! I had a similar idea in mind back when I tried to come up with a solution, but it seemed to me this could end up with a lot of boilerplate code. I had hundreds of structures I needed to do this for, and I was sure that at some point I am going to make a mistake if I do everything manually.

I ended up using built_value and built_union for my serialization needs.