Hive: How to manually create TypeAdapter for class with another class inside?

Created on 18 Oct 2019  路  10Comments  路  Source: hivedb/hive

Is your feature request related to a problem? Please describe.
I have a class like this:

class Orgs {
final String organizationId;
final User user;
}

I've already manually create a TypeAdapter for User. However, how can I create TypeAdapter for Orgs? Because the BinaryWriter don't have any method to write a custom object except primitive type or list.

Describe the solution you'd like
I would like to be able to manually create TypeAdapter for class with class inside.

Version

  • Platform: Android
  • Flutter version: 1.9.1 hotfix 4
  • Hive version: ^1.0.0
question

Most helpful comment

I'm working on support for inheritance. You can already create a custom TypeAdapter.

For the Source class:

class SourceAdapter extends TypeAdapter<Source> {

  @override
  Source read(BinaryReader reader) {
    return Source()
      ..id = reader.read()
      ..name = reader.read();
  }

  void write(BinaryWriter writer, Source obj) {
    writer.write(obj.id);
    writer.write(obj.name);
  }
}

All 10 comments

You are not right, hive working perfect with custom types instead of primitives. Check generated files for Orgs, or create it, and register adapters, good luck =)

@Renesanse Oh, really? I haven't try generated files yet because I create it manually. However in BinaryWriter I don't see any method to write for TypeAdapter-compatible object (in my case is User). Could you tell me that method?

Edit 1: It seems that's method write.write(). Let me try it first.

You need to follow the docs and generate a TypeAdapter. There is no method to write objects since each object consists of primitives and other objects.

Hive writes all the fields individually. Take a look at the generated TypeAdapter.

working fine

@HiveType()
class Source {
  @HiveField(0)
  final String id;
  @HiveField(1)
  final String name;
@HiveType()
class Article {
  @HiveField(0)
  final Source source;
  @HiveField(1)

What if the class belongs to an external package/library,
how do i make a type adapter for that e.g the Source class in the example you gave. I was thinking inheritance but that doesn't work

I'm working on support for inheritance. You can already create a custom TypeAdapter.

For the Source class:

class SourceAdapter extends TypeAdapter<Source> {

  @override
  Source read(BinaryReader reader) {
    return Source()
      ..id = reader.read()
      ..name = reader.read();
  }

  void write(BinaryWriter writer, Source obj) {
    writer.write(obj.id);
    writer.write(obj.name);
  }
}

Hello, how can I register a TypeAdapter for an external class that belong to a flutter package?
Example: I have a image_picker_web package, and I use the MediaInfo as data type, how can I register MediaInfo?

Hello, how can I register a TypeAdapter for an external class that belong to a flutter package?
Example: I have a image_picker_web package, and I use the MediaInfo as data type, how can I register MediaInfo?

Im also wondering the same thing. Need an adapter for GeoPoint

Hello, how can I register a TypeAdapter for an external class that belong to a flutter package?
Example: I have a image_picker_web package, and I use the MediaInfo as data type, how can I register MediaInfo?

Up

Hello, how can I register a TypeAdapter for an external class that belong to a flutter package?
Example: I have a image_picker_web package, and I use the MediaInfo as data type, how can I register MediaInfo?

Yes! You can create TypeAdapter for any class you want! (You will need to write serialization part yourself but It's actually very easy). For example here's a type adapter from our internal code:

import 'package:hive/hive.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:flutter_google_maps/flutter_google_maps.dart';

/// Used for stores geographic location
class GeoCoordinate {
  const GeoCoordinate(this.x, this.y);

  /// [GeoCoordinate] with (0, 0) value
  static const GeoCoordinate zero = const GeoCoordinate(0, 0);

  /// Latitude
  final double x;

  /// Longitude
  final double y;

  @override
  String toString() => '$x,$y';

  GeoCoord toGoogleMapsUnit() => GeoCoord(x, y);

  /// Parse coordinates from [source]. Throws [FormatException] if passed
  /// [source] value is invalid. You can use [tryParse] if you don't want
  /// to catch exception.
  factory GeoCoordinate.parse(String source) {
    if (source == null) {
      return null;
    }
    List<double> parts = source.split(',').map(double.parse).toList();
    if (parts.length != 2) {
      throw FormatException('Invalid value supplied for parsing coordinate.');
    }
    return GeoCoordinate(parts[0], parts[1]);
  }

  /// Parses coordinates from [source]. Returns null if parsing failed.
  static GeoCoordinate tryParse(String source) {
    try {
      return GeoCoordinate.parse(source);
    } on FormatException catch (_) {
      return null;
    }
  }

  factory GeoCoordinate.fromJson(dynamic json) {
    if (json is List) {
      return GeoCoordinate(json[0], json[1]);
    } else if (json is Map) {
      return GeoCoordinate(json['lat'], json['lng']);
    } else if (json is String) {
      return GeoCoordinate.parse(json);
    } else {
      throw FormatException(
          'Unable to convert ${json.runtimeType.toString()} to GeoCoordinate.');
    }
  }
}

class GeoCoordinateConverter implements JsonConverter<GeoCoordinate, String> {
  const GeoCoordinateConverter();

  @override
  GeoCoordinate fromJson(String json) => GeoCoordinate.parse(json);

  @override
  String toJson(GeoCoordinate object) => object.toString();
}

class GeoCoordinateAdapter extends TypeAdapter<GeoCoordinate> {
  @override
  final int typeId = 1;

  @override
  GeoCoordinate read(BinaryReader reader) {
    var x = reader.readDouble();
    var y = reader.readDouble();
    return GeoCoordinate(x, y);
  }

  @override
  void write(BinaryWriter writer, GeoCoordinate obj) {
    writer.writeDouble(obj.x);
    writer.writeDouble(obj.y);
  }

  @override
  int get hashCode => typeId.hashCode;

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is GeoCoordinateAdapter &&
          runtimeType == other.runtimeType &&
          typeId == other.typeId;
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

ninest picture ninest  路  3Comments

yaymalaga picture yaymalaga  路  4Comments

maxim-saplin picture maxim-saplin  路  3Comments

cachapa picture cachapa  路  4Comments

Hopheylalal picture Hopheylalal  路  4Comments