k-paxian / dart-json-mapper

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

Deserialization fails when deserializing a map #96

Closed caneva20 closed 3 years ago

caneva20 commented 3 years ago

Hello @k-paxian!

I'm trying to (de)serialize a Map<String, bool>, but while serialization works fine, when I try to deserialize it, it fails saying my enum is missing annotation, although I'm not using an enum.

I'm not sure if this is a bug or if I am doing something wrong.

Minimum reproducible code:

void main() {
  initializeJsonMapper();

  var json = JsonMapper.serialize(<String, bool>{
    'foo': true,
    'bar': false,
    'bazz': true,
  });

  //This fails
  var map = JsonMapper.deserialize<Map<String, bool>>(json);
}

I even tried using a value decorator, but it didn't seem to help:

initializeJsonMapper(adapters: [
    JsonMapperAdapter(
      valueDecorators: {
        typeOf<Map<String, bool>>(): (value) => value.cast<String, bool>(),
      },
    ),
  ]);

That's the error I'm getting:

E/flutter (10387): [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: It seems your Enum class field is missing annotation:
E/flutter (10387): @JsonProperty(enumValues: null.values)
E/flutter (10387): #0      JsonMapper._deserializeObject (package:dart_json_mapper/src/mapper.dart:798:7)
E/flutter (10387): #1      JsonMapper._configureConverter.<anonymous closure> (package:dart_json_mapper/src/mapper.dart:634:24)
E/flutter (10387): #2      MapConverter.fromJSON.<anonymous closure> (package:dart_json_mapper/src/model/converters.dart:348:31)
E/flutter (10387): #3      MapMixin.map (dart:collection/maps.dart:170:28)
E/flutter (10387): #4      MapConverter.fromJSON (package:dart_json_mapper/src/model/converters.dart:347:25)
E/flutter (10387): #5      JsonMapper._getConvertedValue (package:dart_json_mapper/src/mapper.dart:371:25)
E/flutter (10387): #6      JsonMapper._deserializeObject (package:dart_json_mapper/src/mapper.dart:785:11)
E/flutter (10387): #7      JsonMapper.deserialize (package:dart_json_mapper/src/mapper.dart:62:21)
E/flutter (10387): #8      main (package:redacted/main.dart:43:24)
E/flutter (10387): #9      _runMainZoned.<anonymous closure>.<anonymous closure> (dart:ui/hooks.dart:231:25)
E/flutter (10387): #10     _rootRun (dart:async/zone.dart:1190:13)
E/flutter (10387): #11     _CustomZone.run (dart:async/zone.dart:1093:19)
E/flutter (10387): #12     _runZoned (dart:async/zone.dart:1630:10)
E/flutter (10387): #13     runZonedGuarded (dart:async/zone.dart:1618:12)
E/flutter (10387): #14     _runMainZoned.<anonymous closure> (dart:ui/hooks.dart:223:5)
E/flutter (10387): #15     _startIsolate.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:301:19)
E/flutter (10387): #16     _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:168:12)
caneva20 commented 3 years ago

Well, turns out I was a bit of an idiot, I had two adapters, but I thought it didn't matter (it does), it still gives me an error, but it is a different one

E/flutter (10387): [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: type '_InternalLinkedHashMap<dynamic, dynamic>' is not a subtype of type 'Map<String, bool>'
E/flutter (10387): #0      JsonMapper.deserialize (package:dart_json_mapper/src/mapper.dart:62:5)
E/flutter (10387): #1      main (package:redacted/main.dart:38:25)
E/flutter (10387): #2      _runMainZoned.<anonymous closure>.<anonymous closure> (dart:ui/hooks.dart:231:25)
E/flutter (10387): #3      _rootRun (dart:async/zone.dart:1190:13)
E/flutter (10387): #4      _CustomZone.run (dart:async/zone.dart:1093:19)
E/flutter (10387): #5      _runZoned (dart:async/zone.dart:1630:10)
E/flutter (10387): #6      runZonedGuarded (dart:async/zone.dart:1618:12)
E/flutter (10387): #7      _runMainZoned.<anonymous closure> (dart:ui/hooks.dart:223:5)
E/flutter (10387): #8      _startIsolate.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:301:19)
E/flutter (10387): #9      _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:168:12)

This happens without any adapters, the remaining of the code is the same.

update: While testing, I found that if I put the map inside a class it works fine:

@jsonSerializable
class Data {
  final Map<String, bool> _map;

  Data(this._map);
}
k-paxian commented 3 years ago

Indeed, this is not so obvious from the docs I were trying to explain how to do that.

At this very moment you have three options to make this happen

caneva20 commented 3 years ago

Wonderful! Using a template instance solves my problem partially, and to solve it fully I just need to fix a bug in one of my adapters (I have two from a private package).

As this is kinda related, is there any resource (docs or more examples) for creating custom adapters? I have one that "exports" an internal type using a TypeInfoDecorator that I created based on the three adapters you have and one of them (this one) returns null in its default case, because of that I thought it was ok (and it was the easiest to understand), but this is what was causing the first exception that I mentioned. (when I changed to call its super on default it fixed the problem btw)

k-paxian commented 3 years ago

is there any resource (docs or more examples) for creating custom adapters?

Not yet, all I have is the existing adapters here So the best way as of now is to dig into them 😄 and figure out how it might look like.

The whole adapters concept is not stabilized yet, I'm still gathering use cases from issues to make the adapters contract more mature.

caneva20 commented 3 years ago

Ah, ok that's fair!

I can share the ones I've created, if that's of any help to you, they are quite simple though.

k-paxian commented 3 years ago

As of fixnum TypeInfoDecorator I should fix that, since literally no one is using it, I've not got any issues related, so it stayed like this returning null happily.

It make sense to share adapters which are reusable across the projects, mostly based on popular 3rd party libraries.

Let me know if this issue can be closed.