Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using subtypes in boxes #893

Closed
juleshyacinthe opened this issue Jan 27, 2022 · 3 comments · Fixed by #927
Closed

Using subtypes in boxes #893

juleshyacinthe opened this issue Jan 27, 2022 · 3 comments · Fixed by #927
Labels
question Further information is requested

Comments

@juleshyacinthe
Copy link

juleshyacinthe commented Jan 27, 2022

Question
I have a class User which is inherited by another class UserA. I have another class Order that uses UserA in different properties. When I put orders in a Hive box, everything looks ok. However, after a restart, UserA objects are always parsed as User objects, and when I try to get orders from my box I get an error in the Order reader. I don't really understand why and didn't find a solution browsing this repo's issues. The generated adapters look good to me, but I may be missing something.
The error I get is type 'User' is not a subtype of type 'UserA' in type cast.

Code sample

@HiveType(typeId: 0)
class User extends HiveObject {
  @HiveField(0)
  final String id;
  @HiveField(2)
  String firstName;
  @HiveField(3)
  String lastName;
  ...
}

@HiveType(typeId: 1)
class UserA extends User {
  @HiveField(4)
  String phoneNumber;
...
}

@HiveType(typeId: 3)
class Order extends ChangeNotifier implements Comparable<Order> {
 @HiveField(0)
  final String id;
  ...
  @HiveField(16)
  final UserA by;
  ...
}

class UserAdapter extends TypeAdapter<User> {
  @override
  final int typeId = 0;

  @override
  User read(BinaryReader reader) {
    final numOfFields = reader.readByte();
    final fields = <int, dynamic>{
      for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
    };
    return User(
      id: fields[0] as String,
      firstName: fields[2] as String,
      lastName: fields[3] as String,
    );
  }
...
}

class UserAAdapter extends TypeAdapter<UserA> {
  @override
  final int typeId = 1;

  @override
  UserA read(BinaryReader reader) {
    final numOfFields = reader.readByte();
    final fields = <int, dynamic>{
      for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
    };
    return UserA(
      id: fields[0] as dynamic,
      firstName: fields[2] as dynamic,
      lastName: fields[3] as dynamic,
      phoneNumber: fields[4] as dynamic,
    );
  }
...
}

class OrderAdapter extends TypeAdapter<Order> {
  @override
  final int typeId = 3;

  @override
  Order read(BinaryReader reader) {
    final numOfFields = reader.readByte();
    final fields = <int, dynamic>{
      for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
    };
    return Order(
      fields[0] as String,
      ...
      by: fields[16] as UserA,
      ...
    );
  }
...
}

// Adapter registration is done in this order:
initHive() async {
  await Hive.initFlutter();
  Hive
    ..registerAdapter<User>(UserAdapter())
    ..registerAdapter<UserA>(UserAAdapter())
    ..registerAdapter<Order>(OrderAdapter());
}

Version

  • Platform: iPhone SE 2020 (iOS 15.3)
  • Flutter version: 2.8.1
  • Hive version: 2.0.5
@juleshyacinthe juleshyacinthe added the question Further information is requested label Jan 27, 2022
@saibotma
Copy link
Contributor

What was the solution to your problem?

@juleshyacinthe
Copy link
Author

juleshyacinthe commented Mar 11, 2022

@saibotma it looks like the correct way to deal with inheritance is to register the child classes adapters before registering the inherited class' adapter.

In my case I no longer encounter any issue when registering my adapters like this:

initHive() async {
  await Hive.initFlutter();
  Hive
    ..registerAdapter<UserA>(UserAAdapter())
    ..registerAdapter<User>(UserAdapter())
    ..registerAdapter<Order>(OrderAdapter());
}

@DaliaPinto23
Copy link

@saibotma it looks like the correct way to deal with inheritance is to register the child classes adapters before registering the inherited class' adapter.

In my case I no longer encounter any issue when registering my adapters like this:

initHive() async {
  await Hive.initFlutter();
  Hive
    ..registerAdapter<UserA>(UserAAdapter())
    ..registerAdapter<User>(UserAdapter())
    ..registerAdapter<Order>(OrderAdapter());
}

@juleshyacinthe Thanks, it works for me!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants