How to serialize Uint8List to json with json_annotation in Dart?

Viewed 3272

I made a simple class that has an Uint8List member:

import "package:json_annotation/json_annotation.dart";
part "openvpn.g.dart";

@JsonSerializable()
class OpenVPN extends VPN {
  OpenVPN(Uint8List profile) {
    this.profile = profile;
  }
  /...
  Uint8List profile = null;

However, when running build runner on it to generate the json serializers, I get:

Could not generate `fromJson` code for `profile`.
None of the provided `TypeHelper` instances support the defined type.
package:my_app/folder/openvpn.dart:19:13
   ╷
19 │   Uint8List profile = null;
   │             ^^^^^^^

Is there a way to write my own serializer for this type? Or is there an easier way? I don't want to have a string on the json file, I want to have the actual bytes. It's a small file so it makes sense to store as an array of bytes inside a json.

2 Answers

Add custom JSON converter for Uint8List

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

class Uint8ListConverter implements JsonConverter<Uint8List, List<int>> {
  const Uint8ListConverter();

  @override
  Uint8List fromJson(List<int> json) {
    if (json == null) {
      return null;
    }

    return Uint8List.fromList(json);
  }

  @override
  List<int> toJson(Uint8List object) {
    if (object == null) {
      return null;
    }

    return object.toList();
  }
}

Use Uint8ListConverter on Uint8List propertie. In your case:

import 'package:json_annotation/json_annotation.dart';
import 'dart:typed_data';
import 'package:.../uint8_list_converter.dart';

part 'open_vpn.g.dart';

@JsonSerializable(explicitToJson: true)
class OpenVPN {
  OpenVPN({this.profile});

  @Uint8ListConverter()
  Uint8List profile = null;

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

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

In root project path, run from terminal to generate open_vpn.g.dart partial file: flutter packages pub run build_runner build --delete-conflicting-outputs

In your OpenVPN serialization method, convert the Uint8List into a List<int>. Depending on your implementation, it may look something like:

class OpenVPN {
  factory OpenVPN.fromJson(dynamic map) {
    return OpenVPN(
        ...
        profile: Uint8List.fromList(map['profile'] ?? []),
    );
  }

  toJson() {
    return {
      ...
      'profile': profile as List<int>,
    };
  }
}
Related