freezed icon indicating copy to clipboard operation
freezed copied to clipboard

Support deserializing unions with no "type" property but instead a different shape

Open hacker1024 opened this issue 3 years ago • 6 comments

Is your feature request related to a problem? Please describe. The API I'm using provides data like so:

{
  "generalData": {}
  "catInfo" {},
}
{
  "generalData": {}
  "dogInfo" {},
}

I have a freezed class for the generalData, and several freezed union types for Info.

At the moment, there's no way to choose an Info type based on the key.

Describe the solution you'd like Perhaps a JsonConverter could be passed the key as well as the value?

Describe alternatives you've considered There are none (AFAIK).

Additional context

hacker1024 avatar Apr 12 '21 14:04 hacker1024

There's hardly a solution here.
I'd suggest manually writing your fromJson/toJson for such use-case.

Or ideally, modify the json to include a type key:

{
  "generalData": {}
  "catInfo" {},
  "type": "cat"
}
{
  "generalData": {}
  "dogInfo" {},
  "type": "dog"
}

This should allow Freezed to deserialize such class, with:

@Freezed(unionKey: 'type')
class Animal with _$Animal {
  factory Animal.cat(GeneralData generalData, CatInfo catInfo) = Cat;
  factory Animal.dog(GeneralData generalData, Dog dogInfo) = Dog;
}

rrousselGit avatar Apr 12 '21 15:04 rrousselGit

I'd suggest manually writing your fromJson/toJson for such use-case.

If I try to do that, the union fromJson functions don't get generated.

Or ideally, modify the json to include a type key

Unfortunately, I don't control the API I'm using.

hacker1024 avatar Apr 13 '21 08:04 hacker1024

If I try to do that, the union fromJson functions don't get generated.

Yes, but that's expected.

rrousselGit avatar Apr 13 '21 13:04 rrousselGit

This is perfect - thank you for the question and answer @rrousselGit @hacker1024

ken-ng-esotec avatar May 30 '21 11:05 ken-ng-esotec

Looking back at this, it's probably reasonably doable by checking the Map's length and a bunch of json.containsKey(someKey)

It's fairly advanced and low priority for me though.

rrousselGit avatar May 27 '22 10:05 rrousselGit

Would be a nice feature if you have to support third party APIs. Overall I think it's a bad API design which should be avoided in the first place..

matsp avatar Jun 21 '22 08:06 matsp

You could do this on your own reasonably well with Dart 3

@Freezed(fromJson: true, toJson: true)
class Example with _$Example {
  factory Example.a(int count) = ExampleA;
  factory Example.b(String name) = ExampleB;

  factory Example.fromJson(Map<String, Object?> json) {
    return switch (json) {
      {'count': int()} => ExampleA.fromJson(json),
      {'name': String()} => ExampleB.fromJson(json),
       _ => throw FormatException(),
    };
  }
}

Doing it automatically in Freezed sounds a bit error-prone because the order matters quite a bit in case of potential conflict. Even more so when considering nullable fields & such.

rrousselGit avatar May 24 '23 14:05 rrousselGit

Although interesting, I have currently no plan to implement this. So I'll close this

rrousselGit avatar May 24 '23 14:05 rrousselGit