目的
JSON::XSを使って、$c->render(json => ...)を高速化したい。
Mojo::JSON::XSの設定
Mojo::JSON互換のインタフェースを実装したMojo::JSON::XSを使う。
$ cpanm JSON::XS Mojo::JSON::XS
以下のように、render(json => ...)で、このモジュールを使うように置き換える設定をする。
use Mojolicious::Lite;
use Mojo::JSON::XS;
...
app->renderer->add_handler(json => sub {
my ($self, $c, $output, $options) = @_;
$$output = Mojo::JSON::XS->new->encode($options->{json});
});
...
Mojo::ByteStreamが渡された時の対策
以下のように、
Mojo::ByteStreamのオブジェクトを渡すと、エラーが出てしまう。
use Mojolicious::Lite;
use Mojo::JSON::XS;
use Mojo::ByteStream 'b';
app->renderer->add_handler(json => sub {
my ($self, $c, $output, $options) = @_;
$$output = Mojo::JSON::XS->new->encode($options->{json});
});
get '/' => sub {
my $self = shift;
$self->render(json => {name => b('太郎')});
};
app->start;
「encountered object '太é', but neither allow_blessed, convert_blessed nor allow_tags settings are enabled (or TO_JSON/FREEZE method missing)」
のようなエラーが出る。
通常は、オーバーロードでMojo::ByteStreamのto_stringメソッドが呼び出されるが、
JSON::XSの内部ではblessed判定をしてエラーを出している。
JSON::XSは変換処理をするために、
内部で対象のオブジェクトに対してTO_JSONメソッドを呼び出している。
以下のようにMojo::ByteStreamにTO_JSONメソッドを追加する。
use Mojolicious::Lite;
use Mojo::JSON::XS;
use Mojo::ByteStream 'b';
app->renderer->add_handler(json => sub {
my ($self, $c, $output, $options) = @_;
$$output = Mojo::JSON::XS->new->encode($options->{json});
});
{
no strict 'refs';
*{"Mojo::ByteStream::TO_JSON"} = sub {
my $self = shift;
$self->to_string; # 自身を文字列に変換する
};
}
get '/' => sub {
my $self = shift;
$self->render(json => {name => b('太郎')});
};
app->start;
これで無事にエラーが出なくなる。