jonathanstowe / JSON-Class

A Role to allow Raku objects to be constructed and serialised from/to JSON.
Artistic License 2.0
6 stars 6 forks source link

Hash of Array of JSON::Array #8

Open FCO opened 3 years ago

FCO commented 3 years ago

Is there someway of doing something like this?

raku -MJSON::Class -e '

class TestObject does JSON::Class {
    has Str $.string;
}

constant TestObjects = (Array[TestObject] but JSON::Class);

class Bla does JSON::Class {
    has TestObjects %.aaa;
}

my $json = q<{"aaa": [{ "string" : "one" }, { "string" : "two" }]}>;

say Bla.from-json: $json

'
Type check failed in assignment to %!aaa; expected Array[TestObject]+{JSON::Class} but got Array ([TestObject.new(stri...)
  in sub _unmarshal at /Users/fernando/.rakubrew/versions/moar-2020.11/share/perl6/site/sources/BD58585C8BB103CC821AB89EFD8D30DA4FB8FDF9 (JSON::Unmarshal) line 112
  in sub unmarshal at /Users/fernando/.rakubrew/versions/moar-2020.11/share/perl6/site/sources/BD58585C8BB103CC821AB89EFD8D30DA4FB8FDF9 (JSON::Unmarshal) line 158
  in method from-json at /Users/fernando/.rakubrew/versions/moar-2020.11/share/perl6/site/sources/C0029D661A8CA443DB83A67FE58F3E10D590C1A0 (JSON::Class) line 91
  in block <unit> at -e line 19
jonathanstowe commented 3 years ago

Hi, looking at the JSON I think you don't need that to be a hash rather a Positional there:

use JSON::Class;

class TestObject does JSON::Class {
    has Str $.string;
}

class Bla does JSON::Class {
    has TestObject @.aaa;
}

my $json = q<{"aaa": [{ "string" : "one" }, { "string" : "two" }]}>;

say Bla.from-json: $json

If you actually want to deserialise a bare Hash containing an array of objects then you have to go one step further:

use JSON::Class;

class TestObject does JSON::Class {
    has Str $.string;
}

constant TestObjects := (Array[TestObject] but JSON::Class);
constant Bla         := (Hash[TestObjects] but JSON::Class);

my $json = q<{"aaa": [{ "string" : "one" }, { "string" : "two" }]}>;

say Bla.from-json: $json

Which gives you:

{aaa => [TestObject.new(string => "one") TestObject.new(string => "two")]}