k-paxian / dart-json-mapper

Serialize / Deserialize Dart Objects to / from JSON
https://pub.dev/packages/dart_json_mapper
Other
402 stars 33 forks source link

enumValues from local packages #92

Closed Norbert515 closed 4 years ago

Norbert515 commented 4 years ago

When an enum is declared in a local package

@jsonSerializable
enum Test {
  one, two
}

and is used in another package

void main() async {
  initializeJsonMapper();

  var it = JsonMapper.toMap(SomeOtherClass(Test.one));
  print(it);
}

@jsonSerializable
class SomeOtherClass {

  SomeOtherClass(this.t);

  final Test t;

}

enumValues are not captured in main.mapper.g.dart:

void _initializeReflectable() {
  r.data = _data;
  r.memberSymbolMap = _memberSymbolMap;
}

final mainAdapter = JsonMapperAdapter(
  title: 'mainAdapter',
  url: 'package:json_mapper_error_report/main.dart',
  valueDecorators: {
    typeOf<List<SomeOtherClass>>(): (value) => value.cast<SomeOtherClass>(),
    typeOf<Set<SomeOtherClass>>(): (value) => value.cast<SomeOtherClass>()
},
  enumValues: {

});

JsonMapper initializeJsonMapper({Iterable<JsonMapperAdapter> adapters = const []}) {
  _initializeReflectable();
  [...adapters, mainAdapter].forEach((x) => JsonMapper().useAdapter(x));
  return JsonMapper();
}
k-paxian commented 4 years ago

and is used in another package

You should register your enum from external package manually via adapter as stated in the readme. https://github.com/k-paxian/dart-json-mapper#enum-types

As you have already discovered, enums are automatically registered for local package only.

Norbert515 commented 4 years ago

The readme states

Enums from third party packages, they can not be annotated.

but I certainly can (and have) annotated the enums from said package. Is there any reason for this limitation?

It is pretty common to split up an app into different modules (some being purely dart) at some point. Registering them in the main adapter works, but in that case, it would be easier to have the enumValues property back so the responsibility isn't scattered around the code.

k-paxian commented 4 years ago

There is a slightly better way to chain adapters from libraries you own. Let's imagine you have two libraries A,B and third party library C:

libraryA.dart

@jsonSerializable
enum Test { one, two }

libraryA.mapper.g.dart

final libraryAAdapter = JsonMapperAdapter(
  title: 'libraryAAdapter',
  enumValues: {
     Test: Test.values
});

libraryB.dart

@jsonSerializable
enum TestB { one, two, three }

libraryB.mapper.g.dart

final libraryBAdapter = JsonMapperAdapter(
  title: 'libraryBAdapter',
  enumValues: {
     TestB: TestB.values
});

libraryC.dart

enum ThirdPartyEnum {  Fizz, Buzz }

And on the target App side you would:

main.dart

void main() async {
  initializeJsonMapper(adapters: [
libraryAAdapter, 
libraryBAdapter,
JsonMapperAdapter(
  enumValues: {
     ThirdPartyEnum: ThirdPartyEnum.values
})
]);

  var it = JsonMapper.toMap(SomeOtherClass(Test.one, TestB.three, ThirdPartyEnum.Fizz));
  print(it);
}

I don't see any responsibility scattering in this example, could you please illustrate what exactly made you think so?

Registering particular enum with adapter you are doing it once per application, whereas using enumValues property on annotations, you are forced to repeat yourself as many times as you refer to this particular enum, which is not aligned with the DRY principle

Norbert515 commented 4 years ago

Gotcha. Yeah, the adapters for different packages definitely work. I was just wondering what the reason for it not automatically picking it up is - but I suppose it could lead to weird cases where it's not clear who is responsible for the initialization.

Thanks for the detailed response!