schultek / dart_mappable

Improved json serialization and data classes with full support for generics, inheritance, customization and more.
https://pub.dev/packages/dart_mappable
MIT License
135 stars 20 forks source link

Subtypes discriminating on Mappable Enums do not de-serialize #200

Closed Mereep closed 3 weeks ago

Mereep commented 1 month ago

Hello,

I got an Enum defined as follows:

@MappableEnum()
enum TransactionType {
  @MappableValue('remove_calendar_entry') REMOVE_CALENDAR_ENTRY,
  @MappableValue('store_calendar_entry') STORE_CALENDAR_ENTRY,
  @MappableValue('change_key_to_calendar_assignment') CHANGE_KEY_TO_CALENDAR_ASSIGNMENT,
}

which I use in a class as follows (Super class)

@MappableClass(
  discriminatorKey: 'type',
  includeSubClasses: [
    RemoveCalendarEntry,
    ChangeKeyToCalendarAssignment,
    StoreCalendarEntry,
  ]
)
abstract class BaseTransaction with BaseTransactionMappable {...}

Childs:

@MappableClass(
    discriminatorValue: TransactionType.CHANGE_KEY_TO_CALENDAR_ASSIGNMENT)
class ChangeKeyToCalendarAssignment extends BaseTransaction

This does serialize fine, however deserializing does not work. This is due (in file class_mapper.dart)

  bool canDecode(Map<String, dynamic> value) {
    var discriminator = discriminatorValue;
    if (identical(discriminator, MappingFlags.useAsDefault)) {
      return true;
    } else if (discriminator is Function) {
      if (discriminator is bool Function(Map<String, dynamic>)) {
        return discriminator(value);
      } else {
        throw AssertionError(
            'Discriminator function must be of type "bool Function(Map<String, dynamic>)".');
      }
    } else if (discriminator == value[discriminatorKey]) {
      return true;
    }

will have discriminator set to the Enum-Type but value[discriminatorKey] is actually the String representation, thus identical and == will fail.

In my eyes this should work. Or do I use it wrong :)


Side Note Althought discriminatorValue does seem to have a support for defining functions (which could be used to sidetrack this), will not work for annotations as

@MappableClass(
    discriminatorValue: (map) => ... ,

cannot be used as a workaround as this is not a const expression.

schultek commented 1 month ago

Enums (or any non-primitive) value are currently not supported. You have to put the string directly.

Regarding functions you can define a top-level or static function and use that.

schultek commented 3 weeks ago

Since I have no plans to change the implementation here I'll go ahead and close the issue.