Convert JSON string to Perl / Moose objects

I have a JSON string like

use JSON::XS qw(decode_json); say Dumper( decode_json($json) ); 

will produce:

 $VAR1 = { 'Fname' => 'SomeFname', 'Lname' => 'SomeLname', 'Addr' => { 'Street => 'Somestreet', 'Zip' => '00000', }, }; 

I am looking for an easy way to "convert" a JSON string (or perl structure) into Perl / Moose objects, for example:

  package My; use Moose; has 'Fname' => (is => 'rw', isa => 'Str'); has 'Lname' => (is => 'rw', isa => 'Str'); has 'Addr' => (is => 'rw', isa => 'My::Addr'); 

and

  package My::Addr; use Moose; has 'Street' => (is => 'rw', isa => 'Str'); has 'Zip' => (is => 'rw', isa => 'Str'); 

The problem consists of two parts:

  • defining a Moose class hierarchy based on a JSON string (once)
  • initialization of object instances with real values ​​from JSON (for each JSON)

I am not very skilled at Moose, so you need links to study this specific problem.

(Moose BIG - so reading everything in CPAN will certainly help, but this is too much to start. Therefore, I am looking for step-by-step training in a real problem - for example, above).

Main questions:

  • Is it possible to generate Moose class determinants (perl source) from a data structure? Is there such a CPAN module?
  • when I received the class hierarchy (for example, I can write them manually if there is no helper here), what is the easiest way to create (initialize) my instances from JSON?
+4
source share
1 answer

Is it possible to generate Moose class determinants (perl source) from a data structure? Is there such a CPAN module?

Yes. However, how you do this will largely depend on what you hope to achieve. The easiest would be to simply create attributes in memory based on JSON. For example, you can create metaclass objects at runtime from a JSON file like this:

 sub infer_class_from_hash { my ($input) = @_; # Makes for ugly class names, but does the job my $meta = Moose::Meta::Class->create_anon_class; for my $key (keys %$input) { my $value = $input->{$key}; my $type; my $coerce = 0; # Handle nested objects in the JSON as Moose objects if (ref $value eq 'HASH') { my $inner_meta = infer_class_from_hash($value); $type = $meta->name; # We provide an automatic HASH -> Class coercion $coerce = 1; } # Assume arrays are always of scalars, could be extended to handle objects elsif (ref $value eq 'ARRAY') { $type = 'ArrayRef', } # Assume anything else is string-ish else { $type = 'Str', } $meta->add_attribute($key => is => 'rw', isa => $type, coerce => $coerce, ); } # Create a coercion that makes instantiating from the JSON tree dead simple use Moose::Util::TypeConstraints; coerce $meta->name => from 'HashRef' => via { $meta->name->new($_) }; no Moose::Util::TypeConstraints; return $meta; } 

Everything that does not even begin to delve into what you could do. You can apply roles, custom base classes, add methods, etc. However, the basics of creating a Moose class on the fly.

If you want to have a code generator that outputs the actual Moose classes as files that can be created once and then loaded later, do whatever you want. I would just write a program that worked the same way above, but outputs a set of .pm files with automatically created Moose class definitions in them.

when I received the class hierarchy (for example, I can write them manually if it is not an assistant here), what is the easiest way to create (initialize) my instances from JSON?

 use JSON qw( from_json ); my $hash = from_json("..."); my $meta = infer_class_from_hash($hash); my $obj = $meta->name->new($hash); 

The key point is how we use Moose type coercion to automatically convert JSON objects read into instances of the Moose class. If you have several serialization schemes, or want to use type restrictions in some other way, you can set up a base class for all of these (in the create_anon_class call), which provided the to_json / from_json to handle the case of nested objects in JSON input.

+5
source

Source: https://habr.com/ru/post/1432078/


All Articles