无法弄清楚为什么Sereal编码器/解码器往返没有返回正确的对象



由于对Storable的憎恨,我决定检查Sereal是否需要序列化。另外,我在Storable的32位/64位跨平台问题上遇到了一些问题,所以我认为这将是一个好时机。

在遇到一些问题后,我将问题归结为以下代码。(我正在持久化一个HTTP::Request对象,因此是示例代码)。

这是我的编码测试,我正在存储到一个文件:

use Sereal::Encoder;
use HTTP::Request;
use HTTP::Headers;
use URI;
my $encoder = Sereal::Encoder->new();
open(my $fh, ">", 'myfile.data') or die $!;
binmode($fh);
my $uri = URI->new('http://www.example.com');
my $headers = HTTP::Headers->new(
    Content_Type => 'application/json',
);
my $http_request = HTTP::Request->new(POST => $uri, $headers, 'bleh');
print $fh $encoder->encode( $http_request );
close($fh);

在同一台机器上(5.18上的相同perl等),我运行以下程序:

use Sereal::Decoder;
use File::Slurp qw(read_file);
use URI;
my $data = read_file('myfile.data') or die $!;
my $dec = Sereal::Decoder->new();
my $decoded = $dec->decode($data);
print $decoded->{_uri}->scheme,"n";

并且运行编码程序的输出,然后解码程序是:

Can't locate object method "scheme" via package "URI::http" at testd.pl line 8.

不管怎样,他真的在唠叨我到底出了什么问题。我最终恢复到Storable,并使用nfreeze来解决Storable的主要问题,但我想知道为什么我尝试转换到Sereal时失败了。

谢谢!

与Storable不同,Sereal在遇到序列化对象时不会自动加载模块。这是Storable的安全问题,因此Sereal正在按预期工作。[1]

在第二个测试程序中调用scheme时,URI::http尚未加载,因此方法调用会导致错误。当URI的构造函数用于"看起来像"其中一个子类的字符串时,URI似乎会加载其子类,例如

URI->new('http://www.stackoverflow.com');

加载URI::http模块。因此,一种解决方案是添加该构造函数的伪调用,以确保加载URI::http,或者手动加载use URI::http。任何一个选项都会导致第二个脚本的print $decoded->{_uri}->scheme行按预期工作,但我认为第二个选项是两害相权取其轻(从URI导入未记录的子模块与专门为其不立即明显的副作用而进行的任意方法调用)。

最新更新