Mojo::JSON TO_JSON Recursion

109 views
Skip to first unread message

Stefan

unread,
Nov 14, 2012, 4:13:27 PM11/14/12
to mojol...@googlegroups.com
Hi, group!

I'm building webapps with Mojolicious and a DBIC backend.  I've got all of my relationships in place.  I want to make use of Mojo::JSON's TO_JSON capability with DBIC's Helper::Row::ToJSON.  It's really fantastic!  ...until I want to subclass my TO_JSON methods and have:

package ::Donor;
sub TO_JSON {
   return {items => $self->items};
}
package ::Item;
sub TO_JSON {
   return {donor => $self->donor};
}

There's infinite recursion here.  I don't know how to get around it!  Perhaps I'm doing something wrong in my DBIC classes.  But that's a discussion for the DBIC group, so I digress...

Which leads me to a solution I found with Mojo::JSON!

sub _encode_values {
    :
    # Blessed reference with TO_JSON method
    if (blessed $value && (my $sub = $value->can('TO_JSON'))) {
      return 'null' if grep { $_ eq ref $value } @{$mojo->{__TO_JSON_DEPTH}};
      push @{$mojo->{__TO_JSON_DEPTH}}, ref $value;
      my $to_json = _encode_values($mojo, $value->$sub($mojo));
      pop @{$mojo->{__TO_JSON_DEPTH}} unless ref $to_json;
      return $to_json;
    }
    :
}

sub json_ancestor {
  my $self = shift;
  return $self->{__TO_JSON_DEPTH}->[$_[0]] if $_[0] =~ /^-?\d$/;  
  return grep { $_ eq $_[0] } @{$self->{__TO_JSON_DEPTH}} if $_[0];
  return @{$self->{__TO_JSON_DEPTH}};
}

This does two things!
  1. It automatically prevents infinite recursion with no changes to your existing DBIC Result classes!  Does it also present unintended consequences?
  2. It allows me to do this in my DBIC Result class:
package ::Donor;
sub TO_JSON {
        my $self = shift;
        my $mojo = shift;
        my $json = {%{$self->next::method}};
        $json->{items} = [$self->items] unless $mojo->json_ancestor('Schema::Result::Item');
        return $json;
}
package ::Item;
sub TO_JSON {
        my $self = shift;
        my $mojo = shift;
        my $json = {%{$self->next::method}};
        $json->{donor} = [$self->donor] unless $mojo->json_ancestor('Schema::Result::Donor');
        return $json;
}

How cool is that?!

So, is this something the Mojolicious community is interested in?  Is this a good idea?  Or should we pawn the problem off to DBIC?

I read the Contributing guide and there's certainly some work for me to do to contribute my code which I'll happily do if I get the declared 2/3 vote!  :D

Thanks for reading!  Looking forward to a response.

Stefan

Sebastian Riedel

unread,
Nov 14, 2012, 4:19:00 PM11/14/12
to mojol...@googlegroups.com
> So, is this something the Mojolicious community is interested in? Is this a good idea? Or should we pawn the problem off to DBIC?
>
> I read the Contributing guide and there's certainly some work for me to do to contribute my code which I'll happily do if I get the declared 2/3 vote! :D

Afraid this would get a -1 vote from me, i do not believe this is a problem Mojolicious should solve.

--
sebastian

Stefan Adams

unread,
Nov 14, 2012, 4:23:56 PM11/14/12
to mojol...@googlegroups.com
Thanks for your vote, sebastian!  Good to know this won't be going anywhere.

Is Mojo::JSON subclassable such that I could provide my own module to provide this functionality?

Sebastian Riedel

unread,
Nov 14, 2012, 4:29:35 PM11/14/12
to mojol...@googlegroups.com
> Thanks for your vote, sebastian! Good to know this won't be going anywhere.

There are 3 more votes, but in this case i think the chances are not good.

--
Sebastian Riedel
http://twitter.com/kraih
http://mojolicio.us

Stefan Adams

unread,
Nov 14, 2012, 5:45:41 PM11/14/12
to mojolicious


On Wed, Nov 14, 2012 at 3:29 PM, Sebastian Riedel <kra...@googlemail.com> wrote:
> Thanks for your vote, sebastian!  Good to know this won't be going anywhere.

There are 3 more votes, but in this case i think the chances are not good.

Thanks again!

On another -- but still related -- note, what do you think about a Mojolicious Plugin that does exactly the same thing??

I wrote the horribly named Mojolicious::Plugin::JSON2 which adds a new horribly named handler json2.  This plugin contains the horribly named MojoX::JSON2 which is just a copy of Mojo::JSON with my originally proposed changes.

Do you think this is a good idea?  Would the community welcome this as a plugin?  An automatic JSON renderer with deep recursion protection!

If so, can the community 1) help me come up with a better name and 2) help me figure out how to get:

     $self->respond_to(json => {json2 => $resultset});

to function properly?  Right now it just tries to render "request.json.ep"

I grabbed my plugin code from WriteExcel.

Thanks everyone -- especially Sebastian -- for at least humoring my discussion of this topic.

Sebastian Riedel

unread,
Nov 14, 2012, 5:53:44 PM11/14/12
to mojol...@googlegroups.com
> On another -- but still related -- note, what do you think about a Mojolicious Plugin that does exactly the same thing??

To me it looks like you're trying to fix it on the wrong layer, how could this not be a DBIC issue?

Stefan Adams

unread,
Nov 14, 2012, 6:05:08 PM11/14/12
to mojol...@googlegroups.com
On Wed, Nov 14, 2012 at 4:53 PM, Sebastian Riedel <kra...@googlemail.com> wrote:
> On another -- but still related -- note, what do you think about a Mojolicious Plugin that does exactly the same thing??

To me it looks like you're trying to fix it on the wrong layer, how could this not be a DBIC issue?

That's where my focus was initially but Mojo::JSON seemed to address it so easily.  I'll return my focus back to DBIC and address my issues with that community.  It helps just knowing which layer I should be dealing with.

Thanks again and a huge thank you for Mojolicious.  It's the holy grail of web frameworks.
 
Reply all
Reply to author
Forward
0 new messages