GithubHelp home page GithubHelp logo

jonathanstowe / json-class Goto Github PK

View Code? Open in Web Editor NEW
6.0 2.0 6.0 50 KB

A Role to allow Raku objects to be constructed and serialised from/to JSON.

License: Artistic License 2.0

Raku 100.00%
json serialisation raku object

json-class's Introduction

JSON::Class

A Role to allow Raku objects to be constructed and serialised from/to JSON.

Build Status

Synopsis

    use JSON::Class;

    class Something does JSON::Class {
 
        has Str $.foo;

    }

    my Something $something = Something.from-json('{ "foo" : "stuff" }');

    ...

    my Str $json = $something.to-json(); # -> '{ "foo" : "stuff" }'

or with 'opt-in' serialization:

    use JSON::Class;
    use JSON::OptIn;

    class Something does JSON::Class[:opt-in] {
 
        has Str $.foo is json;
        has Str $.secret = 'secret';

    }

    my Something $something = Something.from-json('{ "foo" : "stuff" }');

    ...

    my Str $json = $something.to-json(); # -> '{ "foo" : "stuff" }'

Description

This is a simple role that provides methods to instantiate a class from a JSON string that (hopefully,) represents it, and to serialise an object of the class to a JSON string. The JSON created from an instance should round trip to a new instance with the same values for the "public attributes". "Private" attributes (that is ones without accessors,) will be ignored for both serialisation and de-serialisation. The exact behaviour depends on that of JSON::Marshal and JSON::Unmarshal respectively.

If the :skip-null adverb is provided to to-json all attributes without a defined value will be ignored in serialisation. If you need finer grained control then you should apply the json-skip-null attribute trait (defined by JSON::Marshal ) to the attributes you want to skip if they aren't defined (:skip-null will still have the same effect though.)

If you don't need prettified, human readable JSON output then you can supply the :!pretty adverb to to-json.

The JSON::Marshal and JSON::Unmarshal provide traits for controlling the unmarshalling/marshalling of specific attributes which are re-exported by the module.

If your application exposes the marshalled data via, for example, an API, then you may choose to use the :opt-in parameter to the role, which will cause only those attributes that are explicitly marked to be marshalled, avoiding the risk of inadvertently exposing sensitive data. This is described in more detail in JSON::Marshal.

Installation

Assuming you have a working Rakudo installation you should be able to install this with zef :

# From the source directory

zef install .

# Remote installation

zef install JSON::Class

Support

Suggestions/patches are welcomed via github at:

https://github.com/jonathanstowe/JSON-Class

Licence

This is free software.

Please see the (LICENCE)[LICENCE] file in the distribution for the details.

© Jonathan Stowe 2015, 2016, 2017, 2019, 2020, 2021

json-class's People

Contributors

b2gills avatar jonathanstowe avatar ugexe avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

json-class's Issues

Possible re-work of JSON::Class

There is a little but non-zero chance that I'd be working on an alternate implementation for JSON::Class because I need something more configurable and extensible. Unfortunately, JSON::Class -> JSON::Unmarshal/Marshal lacks necessary scalability. I'd like to get something akin to LibXML::Class and XML::Class.

The question is about naming. It would be great if the re-work follows the kind of standard naming approach and, yes, be named JSON::Class. With zef ecosystem this is not a big deal as the author name would be different. But I'd like to synchronize the matter with you and know your opinion on this.

Alternatively, I can simply re-implement this module and submit a PR.

Once again, it is all in limbo now. I have an immediate solution for my current problem in mind, even though it requires either to somehow make marshal return raw structure (hash, list, whatever), or de-deserialize the JSON it produces (slow!).

Hash of Array of JSON::Array

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

Custom class type objects (undefined) fail round trip conversion / can't be serialized

Builtin (undefined) types are serialized as null. This works well:

> (Int but JSON::Class).to-json
null
> (Str but JSON::Class).to-json
null
> (Int but JSON::Class).from-json: (Int but JSON::Class).to-json;
(Int+{Class})

Custom classes should be serialized the same way. Instead, they're serialized the same way as a defined class, and this either causes round-trip conversion failure, or an exception, depending on whether the class has members:

> class C does JSON::Class { }
> C.to-json;
{
}
> C.from-json: C.to-json;
C.new
> class D does JSON::Class { has $.i; }
> D.to-json;
Cannot look up attributes in a D type object
  in block  at D:\rakudo-2017.12\share\perl6\site\sources\0D5D5ABC9DC9B8DB1F75571789AD2F8F5FD3487A (JSON::Marshal) line 143
  in sub _marshal at D:\rakudo-2017.12\share\perl6\site\sources\0D5D5ABC9DC9B8DB1F75571789AD2F8F5FD3487A (JSON::Marshal) line 132
  in sub marshal at D:\rakudo-2017.12\share\perl6\site\sources\0D5D5ABC9DC9B8DB1F75571789AD2F8F5FD3487A (JSON::Marshal) line 172
  in method to-json at D:\rakudo-2017.12\share\perl6\site\sources\AEC54816C1D35CBEB0033396AD685FA76A800D6E (JSON::Class) line 94
  in block <unit> at <unknown file> line 1

External opt-in

I was wondering, if I have a class that I want to use in 2 different places, but one is a external route and the other is an internal one. Then probably on both places I would want to "export" different attributes. Would have a way to do something like:

class Bla does JSON::Class[:externally-opt-in] {
   has $.private;
   has $.internal;
   has $.external;
}

my Bla $bla .= new: :1private, :2internal, :3external;



# on internal route:
$bla.to-json: :opt-in<internal external>; # { "internal": 2, "external": 3 }

# on external route:
$bla.to-json: :opt-in<external>; # { "external": 3 }

# and not specifying the attributes could die or return `null`



# or maybe even:

# on internal route:
my $internal-bla = $bla.opt-in: <internal external>;
$internal-bla.to-json; # { "internal": 2, "external": 3 }

# on external route:
my $external-bla = $bla.opt-in: <external>;
$external-bla.to-json; # { "external": 3 }



# or even:

# on internal route:
my %*JSON-Class-opt-in{Bla} = <internal external>;
$bla.to-json; # { "internal": 2, "external": 3 }

# on external route:
my %*JSON-Class-opt-in{Bla} = <external>;
$bla.to-json; # { "external": 3 }

I personally like the dynvar one because if I define it on my route, doesn't matter what I do with the object, it will never leak data...
Or something like that? If it already has something like that, I'm sorry.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.