对象序列化器

用于以各种方式(JSON、通用对象)序列化数据的集合。

版本:0.1.5

目前有两种数据序列化器可用

  • JSON 序列化器
  • 对象序列化器

JSON 序列化器 是一个标准 JSON 格式的序列化器。支持转换为更简单数据类型的类型(例如 BigIntDateTimeDurationUri 等)的序列化。工作原理很简单。您自己选择数据序列化和反序列化方法,也就是说,您完全控制此过程。

对象序列化器 是任何静态(通用)复杂数据的序列化器(支持缓存),这些数据可以表示为更简单的数据。

允许您为可以在 isolat 之间或甚至在 Internet 上传输的任何数据实现序列化器。操作原理非常简单,对于每种数据类型,您都需要实现自己的对象序列化器。

实现对象序列化器也非常简单。为此,您需要以严格的顺序写入数据,然后在相同的顺序读取这些数据。

JSON

假设我们需要使用这些数据对象。

class Company {
  final String name;

  final Uri website;

  Company({
    required this.name,
    required this.website,
  });
}

class Customer {
  final int? age;

  final DateTime? birthday;

  final Duration frequency;

  final CustomerLevel level;

  final String name;

  Customer({
    required this.age,
    required this.birthday,
    required this.frequency,
    required this.level,
    required this.name,
  });
}

enum CustomerLevel { retail, wholesale }

class Order {
  final BigInt amount;

  final Company company;

  final Customer customer;

  final DateTime date;

  final List<OrderLine> lines;

  Order({
    required this.amount,
    required this.company,
    required this.customer,
    required this.date,
    required this.lines,
  });
}

class OrderLine {
  final Product product;

  final BigInt price;

  final int quantity;

  final BigInt total;

  OrderLine({
    required this.product,
    required this.price,
    required this.quantity,
    required this.total,
  });
}

class Product {
  final String name;

  final BigInt price;

  final Map<String, double> priceRange;

  Product({
    required this.name,
    required this.price,
    required this.priceRange,
  });
}

如何在不到 30 分钟的时间内为这些数据类型实现序列化器?让我们尝试一下。

class _BigIntSerializer extends JsonSerializer<BigInt> {
  @override
  BigInt deserialize(Deserializer deserializer, Object? value) {
    final json = cast<String>(value);
    return BigInt.parse(json);
  }

  @override
  String serialize(Serializer serializer, BigInt value) {
    return value.toString();
  }
}

class _CompanySerializer extends JsonSerializer<Company> {
  @override
  Company deserialize(Deserializer deserializer, Object? value) {
    final json = cast<Map>(value);
    return Company(
      name: deserializer.deserialize(json['name']),
      website: deserializer.deserialize(json['website']),
    );
  }

  @override
  Map<String, dynamic> serialize(Serializer serializer, Company value) {
    return {
      'name': serializer.serialize(value.name),
      'website': serializer.serialize(value.website),
    };
  }
}

class _CustomerLevelSerializer extends JsonSerializer<CustomerLevel> {
  @override
  CustomerLevel deserialize(Deserializer deserializer, Object? value) {
    final json = cast<int>(value);
    return CustomerLevel.values[json];
  }

  @override
  int serialize(Serializer serializer, CustomerLevel value) {
    return value.index;
  }
}

class _CustomerSerializer extends JsonSerializer<Customer> {
  @override
  Customer deserialize(Deserializer deserializer, Object? value) {
    final json = cast<Map>(value);
    return Customer(
      birthday: deserializer.deserialize(json['birthday']),
      age: deserializer.deserialize(json['age']),
      frequency: deserializer.deserialize(json['frequency']),
      level: deserializer.deserialize(json['level']),
      name: deserializer.deserialize(json['name']),
    );
  }

  @override
  Map<String, dynamic> serialize(Serializer serializer, Customer value) {
    return {
      'age': serializer.serialize(value.age),
      'birthday': serializer.serialize(value.birthday),
      'frequency': serializer.serialize(value.frequency),
      'level': serializer.serialize(value.level),
      'name': serializer.serialize(value.name),
    };
  }
}

class _DateTimeSerializer extends JsonSerializer<DateTime> {
  @override
  DateTime deserialize(Deserializer deserializer, Object? value) {
    final json = cast<String>(value);
    return DateTime.fromMicrosecondsSinceEpoch(int.parse(json));
  }

  @override
  String serialize(Serializer serializer, DateTime value) {
    return value.microsecondsSinceEpoch.toString();
  }
}

class _DurationSerializer extends JsonSerializer<Duration> {
  @override
  Duration deserialize(Deserializer deserializer, Object? value) {
    final json = cast<String>(value);
    return Duration(microseconds: int.parse(json));
  }

  @override
  String serialize(Serializer serializer, Duration value) {
    return value.inMicroseconds.toString();
  }
}

class _OrderLineSerializer extends JsonSerializer<OrderLine> {
  @override
  OrderLine deserialize(Deserializer deserializer, Object? value) {
    final json = cast<Map>(value);
    return OrderLine(
      price: deserializer.deserialize(json['price']),
      product: deserializer.deserialize(json['product']),
      quantity: deserializer.deserialize(json['quantity']),
      total: deserializer.deserialize(json['total']),
    );
  }

  @override
  Map<String, dynamic> serialize(Serializer serializer, OrderLine value) {
    return {
      'price': serializer.serialize(value.price),
      'product': serializer.serialize(value.product),
      'quantity': serializer.serialize(value.quantity),
      'total': serializer.serialize(value.total),
    };
  }
}

class _OrderSerializer extends JsonSerializer<Order> {
  @override
  Order deserialize(Deserializer deserializer, Object? value) {
    final json = cast<Map>(value);
    return Order(
      amount: deserializer.deserialize(json['amount']),
      company: deserializer.deserialize(json['company']),
      customer: deserializer.deserialize(json['customer']),
      date: deserializer.deserialize(json['date']),
      lines: deserializer.deserializeList(json['lines']),
    );
  }

  @override
  Map<String, dynamic> serialize(Serializer serializer, Order value) {
    return {
      'amount': serializer.serialize(value.amount),
      'company': serializer.serialize(value.company),
      'customer': serializer.serialize(value.customer),
      'date': serializer.serialize(value.date),
      'lines': serializer.serializeList(value.lines),
    };
  }
}

class _ProductSerializer extends JsonSerializer<Product> {
  @override
  Product deserialize(Deserializer deserializer, Object? value) {
    final json = cast<Map>(value);
    return Product(
      name: deserializer.deserialize(json['name']),
      price: deserializer.deserialize(json['price']),
      priceRange: deserializer.deserializeMap(json['priceRange']),
    );
  }

  @override
  Map<String, dynamic> serialize(Serializer serializer, Product value) {
    return {
      'name': serializer.serialize(value.name),
      'price': serializer.serialize(value.price),
      'priceRange': serializer.serializeMap(value.priceRange),
    };
  }
}

class _UriSerializer extends JsonSerializer<Uri> {
  @override
  Uri deserialize(Deserializer deserializer, Object? value) {
    final json = cast<String>(value);
    return Uri.parse(json);
  }

  @override
  String serialize(Serializer serializer, Uri value) {
    return value.toString();
  }
}

大约 180 行代码。考虑到您对序列化的内容和方式拥有完全的控制权,这并不算多。

让我们看看这项工作的实际结果。最简单的测试

import 'dart:convert';

import 'package:object_serializer/json_serializer.dart';

void main(List<String> args) {
  final price = BigInt.from(29.99);
  final order = Order(
    amount: price,
    company: _company,
    customer: _customer,
    date: DateTime.now(),
    lines: [
      OrderLine(
          product: _product,
          price: price,
          quantity: 25,
          total: price * BigInt.from(25))
    ],
  );

  final orders = [order, order];
  final jsonObject = serializeList(orders, _collection);
  final jsonString = jsonEncode(jsonObject);
  final jsonObject2 = jsonDecode(jsonString);
  final orders2 = deserializeList<Order>(jsonObject2, _collection);
  final jsonObject3 = serializeList(orders2, _collection);
  final jsonString2 = jsonEncode(jsonObject3);
  final result = jsonString == jsonString2;
  print(jsonString2);
  print('Test passed: $result');
}

final _collection = JsonSerializerCollection()
  ..addSerializer(_BigIntSerializer())
  ..addSerializer(_CompanySerializer())
  ..addSerializer(_CustomerLevelSerializer())
  ..addSerializer(_CustomerSerializer())
  ..addSerializer(_DateTimeSerializer())
  ..addSerializer(_DurationSerializer())
  ..addSerializer(_OrderLineSerializer())
  ..addSerializer(_OrderSerializer())
  ..addSerializer(_ProductSerializer())
  ..addSerializer(_UriSerializer());

final _company = Company(
  name: 'ACME Inc.',
  website: Uri.parse('https://acme.com'),
);

final _customer = Customer(
  age: null,
  birthday: null,
  frequency: Duration(days: 10),
  level: CustomerLevel.wholesale,
  name: 'Peter Pan',
);

final _product = Product(
  name: 'The Little White Bird',
  price: BigInt.from(49.99),
  priceRange: {
    '3': 49.99,
    '10': 39.99,
    '25': 29.99,
  },
);

工作结果

[{“amount”:”29″,”company”:{“name”:”ACME Inc.”,”website”:”https://acme.com”},”customer”:{“age”:null,”birthday”:null,”frequency”:”864000000000″,”level”:1,”name”:”Peter Pan”},”date”:”1658504965053872″,”lines”:[{“price”:”29″,”product”:{“name”:”The Little White Bird”,”price”:”49″,”priceRange”:{“3″:49.99,”10″:39.99,”25″:29.99}},”quantity”:25,”total”:”725″}]},{“amount”:”29″,”company”:{“name”:”ACME Inc.”,”website”:”https://acme.com”},”customer”:{“age”:null,”birthday”:null,”frequency”:”864000000000″,”level”:1,”name”:”Peter Pan”},”date”:”1658504965053872″,”lines”:[{“price”:”29″,”product”:{“name”:”The Little White Bird”,”price”:”49″,”priceRange”:{“3″:49.99,”10″:39.99,”25″:29.99}},”quantity”:25,”total”:”725″}]}] 测试通过:true

对象序列化器

简单的对象序列化器示例

class _UriSerializer extends ObjectSerializer<Uri> {
  @override
  Uri deserialize(Deserializer deserializer) {
    return Uri.parse(deserializer.readObject());
  }

  @override
  void serialize(Serializer serializer, Uri object) {
    serializer.writeObject(object.toString());
  }
}

这不是 JSON 序列化器的模拟或替代品。在这种情况下,数据被序列化到一个所谓的流中,并在需要时进行缓存。

例如,您可以序列化此类数据。

typedef _ComplexType = Map<Uri, List<Tuple2<BigInt, Tuple2<int, Base?>>>>;

class A extends Base {
  A(super.base);

  @override
  bool operator ==(other) => other is A && other.base == base;
}

class B extends Base {
  final int x;

  B(super.base, this.x);

  @override
  bool operator ==(other) => other is B && other.base == base && other.x == x;
}

class Base {
  final String base;

  Base(this.base);
}

例如,可以序列化此类数据。

final _ComplexType map = {
  Uri.parse('package:animals'): [
    Tuple2(BigInt.parse('1'), Tuple2(1, A('Hello'))),
    Tuple2(BigInt.parse('2'), Tuple2(1, A('Hello'))),
  ],
  Uri.parse('package:zoo'): [
    Tuple2(BigInt.parse('1'), Tuple2(1, B('Goodbye', 41))),
    Tuple2(BigInt.parse('2'), Tuple2(2, null)),
    Tuple2(BigInt.parse('1'), Tuple2(1, A('Hello'))),
  ],
};

输出数据流

[1, 4, 2, 4, 16, 6, 8, package:animals, 9, 9, 2, 12, 11, 14, 15, 16, 8, 1, 19, 12, 21, 2, 1, 24, 13, 26, 8, Hello, 29, 11, 31, 15, 33, 8, 2, 36, 12, 21, 39, 13, 26, 42, 16, 44, 8, package:zoo, 47, 9, 3, 50, 11, 14, 53, 12, 21, 56, 14, 58, 8, Goodbye, 61, 2, 41, 64, 11, 31, 67, 12, 69, 2, 2, 72, 6, 74, 11, 14, 77, 12, 21, 80, 13, 26]

完整示例

import 'dart:isolate';

import 'package:object_serializer/object_serializer.dart';
import 'package:object_serializer/serialize.dart';
import 'package:test/test.dart';
import 'package:tuple/tuple.dart';

Future<void> main() async {
  test(
    'Example',
    () async {
      final _ComplexType map = {
        Uri.parse('package:animals'): [
          Tuple2(BigInt.parse('1'), Tuple2(1, A('Hello'))),
          Tuple2(BigInt.parse('2'), Tuple2(1, A('Hello'))),
        ],
        Uri.parse('package:zoo'): [
          Tuple2(BigInt.parse('1'), Tuple2(1, B('Goodbye', 41))),
          Tuple2(BigInt.parse('2'), Tuple2(2, null)),
          Tuple2(BigInt.parse('1'), Tuple2(1, A('Hello'))),
        ],
      };

      final stream = serializeMap(map, _collection);

      //
      final port = ReceivePort();
      final isolate =
          await Isolate.spawn<List>(compute, [port.sendPort, stream]);
      final stream2 = await port.first as List;
      isolate.kill(priority: Isolate.immediate);

      //
      final _ComplexType result = deserializeMap(stream2, _collection);
      expect(result, map);
    },
  );
}

final _collection = ObjectSerializerCollection()
  ..addSerializer(ListSerializer<Tuple2<BigInt, Tuple2<int, Base?>>>())
  ..addSerializer(_ASerializer())
  ..addSerializer(_BSerializer())
  ..addSerializer(_BigIntSerializer())
  ..addSerializer(_Tuple2Serializer<BigInt, Tuple2<int, Base?>>())
  ..addSerializer(_Tuple2Serializer<int, Base?>())
  ..addSerializer(_UriSerializer());

void compute(List args) {
  final sendPort = args[0] as SendPort;
  final input = args[1] as List;
  final _ComplexType map = deserializeMap(input, _collection);
  final output = serializeMap(map, _collection);
  sendPort.send(output);
}

typedef _ComplexType = Map<Uri, List<Tuple2<BigInt, Tuple2<int, Base?>>>>;

class A extends Base {
  A(super.base);

  @override
  bool operator ==(other) => other is A && other.base == base;
}

class B extends Base {
  final int x;

  B(super.base, this.x);

  @override
  bool operator ==(other) => other is B && other.base == base && other.x == x;
}

class Base {
  final String base;

  Base(this.base);
}

class _ASerializer extends ObjectSerializer<A> {
  @override
  A deserialize(Deserializer deserializer) {
    return A(
      deserializer.readObject(),
    );
  }

  @override
  void serialize(Serializer serializer, A object) {
    serializer.writeObject(object.base);
  }
}

class _BigIntSerializer extends ObjectSerializer<BigInt> {
  @override
  BigInt deserialize(Deserializer deserializer) {
    return BigInt.parse(deserializer.readObject());
  }

  @override
  void serialize(Serializer serializer, BigInt object) {
    serializer.writeObject('$object');
  }
}

class _BSerializer extends ObjectSerializer<B> {
  @override
  B deserialize(Deserializer deserializer) {
    return B(
      deserializer.readObject(),
      deserializer.readObject(),
    );
  }

  @override
  void serialize(Serializer serializer, B object) {
    serializer.writeObject(object.base);
    serializer.writeObject(object.x);
  }
}

class _Tuple2Serializer<T1, T2> extends ObjectSerializer<Tuple2<T1, T2>> {
  @override
  Tuple2<T1, T2> deserialize(Deserializer deserializer) {
    return Tuple2(
      deserializer.readObject(),
      deserializer.readObject(),
    );
  }

  @override
  void serialize(Serializer serializer, Tuple2<T1, T2> object) {
    serializer.writeObject(object.item1);
    serializer.writeObject(object.item2);
  }
}

class _UriSerializer extends ObjectSerializer<Uri> {
  @override
  Uri deserialize(Deserializer deserializer) {
    return Uri.parse(deserializer.readObject());
  }

  @override
  void serialize(Serializer serializer, Uri object) {
    serializer.writeObject(object.toString());
  }
}

对于更简单或非通用的数据,需要更少的序列化器。但无论如何,每种数据都需要自己的序列化器。

这使得任何类型的数据都可以被序列化。例如,您可以序列化已解析的 AST。主要目标是使编写序列化器以在 isolat 之间传递数据变得更加容易。

GitHub

查看 Github