FAQ

[Catalyst] Cross-link: How do I turn Moose objects into JSON for use in Catalyst?

Evan Carroll
Aug 3, 2010 at 3:31 pm
I've posted a question and a few possible fixes. Does anyone have
anything to add here? How do you go about dumping Moose to JSON in
Cat?

http://stackoverflow.com/questions/3391967/how-do-i-turn-moose-objects-into-json-for-use-in-catalyst

--
Evan Carroll - me@evancarroll.com
System Lord of the Internets
web: http://www.evancarroll.com
ph: 281.901.0011
reply

Search Discussions

5 responses

  • Alex J. G. Burzyński at Aug 3, 2010 at 4:06 pm
    Hi,
    On 03/08/10 16:31, Evan Carroll wrote:
    I've posted a question and a few possible fixes. Does anyone have
    anything to add here? How do you go about dumping Moose to JSON in
    Cat?

    http://stackoverflow.com/questions/3391967/how-do-i-turn-moose-objects-into-json-for-use-in-catalyst
    That's the method I'm using to dump my classes for AJAX-driven control
    panel.

    Works recursively on my other moose classes (ResultSet::* classes from
    DBIx::BlackBox consume MyApp::DB::ResultSet::Roles::ToJSON).

    Cheers,
    Alex


    package MyApp::DB::ResultSet::Roles::ToJSON;

    use Moose::Role;

    sub TO_JSON {
    my $self = shift;

    my $json_hash = {};

    for my $attr ( $self->meta->get_all_attributes ) {
    my $name = $attr->name;
    $json_hash->{ $name } = $self->$name;
    }

    return $json_hash;
    }

    package MyApp::DB::ResultSet::SuppliersList;

    use Moose;

    with qw(
    MyApp::DB::ResultSet::Roles::ToJSON
    );

    use namespace::autoclean;

    has 'org_id' => (
    is => 'rw',
    isa => 'Str',
    required => 1,
    );
    has 'org_name' => (
    is => 'rw',
    isa => 'Str',
    required => 1,
    );
    has 'number_of_courses' => (
    is => 'rw',
    isa => 'Int',
    default => 0,
    required => 1,
    );
    has 'number_of_enabled_courses' => (
    is => 'rw',
    isa => 'Int',
    default => 0,
    required => 1,
    );


    package MyApp::View::JSON;

    use strict;
    use base 'Catalyst::View::JSON';

    use JSON::XS ();

    my $encoder = JSON::XS
    ->new
    ->utf8
    ->pretty(0)
    ->indent(0)
    ->allow_blessed(1)
    ->convert_blessed(1);

    sub encode_json {
    my($self, $c, $data) = @_;

    $encoder->encode($data);
    }

    package MyApp::Controller::Foo;
    ...

    sub list_suppliers :Local {
    my ( $self, $c ) = @_;

    $c->stash( json => []);

    my $rs = $c->model('DB')->exec('ListSuppliers');
    do {
    while ( my $supplier = $rs->next_row ) {
    push @{ $c->stash->{json} }, $supplier;
    }
    } while ( $rs->next_resultset );

    $c->forward('View::JSON');
    }
  • Evan Carroll at Aug 3, 2010 at 5:11 pm

    The documentation? isn't clear on how, but this implies some combination of
    these flags (probably setting both to true) should do the "encoding the
    reference as if it weren't blessed" thing.
    No, allow_blessed(1) means it will not die, it will instead print out
    the totally useless string 'null'. This is technically allowing a
    blessed scalar. However, convert_blessed, is a total misnomer as
    nothing is /converted/. All that happens is the method TO_JSON is
    called.

    ecarroll@rda:~$ perl -MJSON::XS -E'my $o = bless { foo=>'bar' }; say
    JSON::XS->new->encode( $o );'
    encountered object 'main=HASH(0x7b8df0)', but neither allow_blessed
    nor convert_blessed settings are enabled at -e line 1.

    ecarroll@rda:~$ perl -MJSON::XS -E'my $o = bless { foo=>'bar' }; say
    JSON::XS->new->allow_blessed(1)->encode( $o );'
    null
    ecarroll@rda:~$ perl -MJSON::XS -E'my $o = bless { foo=>'bar' }; say
    JSON::XS->new->allow_blessed(1)->convert_blessed(1)->encode( $o );'
    null

    In this example the object is blessed in the default package main,
    where TO_JSON is called.

    ecarroll@rda:~$ perl -MJSON::XS -E'my $o = bless { foo=>'bar' }; sub
    TO_JSON { "hi" }; say
    JSON::XS->new->allow_blessed(1)->convert_blessed(1)->encode( $o );'
    "hi"


    But yes, ideally /convert_blessed/ would do what I want rather than
    just call a sub that expects me to do it. My handy old XXX.pm does
    this right:

    ecarroll@rda:~$ perl -E'my $o = bless { foo=>'bar' }; use XXX; XXX $o'
    --- !!perl/hash:main
    foo: bar
    ...
    at -e line 1

    --
    Evan Carroll - me@evancarroll.com
    System Lord of the Internets
    web: http://www.evancarroll.com
    ph: 281.901.0011
  • Evan Carroll at Aug 3, 2010 at 8:39 pm

    On Tue, Aug 3, 2010 at 12:34 PM, Stuart Watt wrote:
    You're right - I just checked the sources and there is no valid code for
    this case, despite the implication of the documentation. I'd be tempted to
    file a bug against JSON::XS, as at least the pod is wrong. I guess it got
    too hard, as blessedness does not require a thing to be a hashref. Looks
    like a fairly straightforward test case and patch, though.
    I filed a bug report (feature request) for real object dumping
    https://rt.cpan.org/Ticket/Display.html?id`050

    --
    Evan Carroll - me@evancarroll.com
    System Lord of the Internets
    web: http://www.evancarroll.com
    ph: 281.901.0011
  • Evan Carroll at Aug 3, 2010 at 8:56 pm
    It also appears as if YAML::Syck does this very well:

    perl -MJSON::Syck -MURI -E'say JSON::Syck::Dump( bless { foo =>
    URI->new("http://www.evancarrol.com") } )'

    --
    Evan Carroll - me@evancarroll.com
    System Lord of the Internets
    web: http://www.evancarroll.com
    ph: 281.901.0011
  • Tomas Doran at Aug 4, 2010 at 12:29 pm

    On 3 Aug 2010, at 17:31, Evan Carroll wrote:

    I've posted a question and a few possible fixes. Does anyone have
    anything to add here? How do you go about dumping Moose to JSON in
    Cat?
    I use MooseX::Storage, as per perigrin's comment on the stack overflow
    post.

    Cheers
    t0m

Related Discussions

Discussion Navigation
viewthread | post