Как преобразовать объекты Perl в JSON и наоборот
Я определил объект Point в файле Point.pm
следующим образом:
package Point;
sub new {
my ($class) = @_;
my $self = {
_x => 0,
_y => 0,
};
return bless $self => $class;
}
sub X {
my ($self, $x) = @_;
$self->{_x} = $x if defined $x;
return $self->{_x};
}
sub Y {
my ($self, $y) = @_;
$self->{_y} = $y if defined $y;
return $self->{_y};
}
1;
Теперь, когда я использую JSON для преобразования объекта в JSON с помощью следующего кода:
use JSON;
use Point;
Point $p = new Point;
$p->X(20);
$p->Y(30);
my $json = encode_json $p;
Я получаю следующую ошибку:
encountered object 'Point=HASH(0x40017288)', but neither allow_blessed nor convert_blessed settings are enabled at test.pl line 28
Как преобразовать в и из JSON объект, используя модуль JSON?
4 ответа
Предупреждение говорит вам о том, что не так. Если вы не скажете JSON
как обрабатывать благословенные ссылки (объекты Perl), JSON
обрабатывает только неблаженные структуры данных.
Вы можете convert_blessed
и ты можешь allow_blessed
, За allow_blessed
, это говорит:
Если
$enable
имеет значение false (по умолчанию), тогда закодировать сгенерирует исключение при обнаружении благословенного объекта.
Точка является классом объекта, таким образом, экземпляр Point
является благословенной ссылкой, и, следовательно, по умолчанию для JSON
это бросить исключение.
Если вы включите convert_blessed
, это будет называть TO_JSON
метод на вашем объекте. С простыми объектами, такими как Point
(те, которые не содержат благословенных членов), вы можете сделать это так же легко, как:
sub TO_JSON { return { %{ shift() } }; }
Если вам придется спускаться по структуре, это станет намного более опасным.
Кто-то в комментариях ниже сказал, что я не рассказал о том, как получить объекты из JSON.
Основы просты. Так что здесь идет
my $object = bless( JSON->new->decode( $json_string ), 'ClassIWant' );
В основном я рассмотрел часть, которая не позволяет вам просто сериализовать благословенный объект в JSON.
Основы десериализации просты, как и основы сериализации просты - как только вы знаете хитрость. На этом пути нет ошибок, есть только задача найти то, что вам нужно, и благословить его в нужном классе.
Если вы хотите, чтобы код был связан с объектами, тогда вы будете знать, что должно быть благословлено и во что оно должно быть благословлено. Если вам нужен полностью отделенный код, в Perl это не сложнее и проще, чем в самом JavaScript.
Вам нужно будет сериализовать маркер в JSON. Если мне нужно что-то вроде этого, я вставлю '__CLASS__'
поле в благословенные предметы. И при десериализации я спущусь через структуру и благословлю все, как это:
bless( $ref, delete $ref->{__CLASS__} );
Но, как я уже сказал, в Perl это не легче и не сложнее, потому что JSON представляет одну и ту же проблему для всех языков.
Как Шверн предложил в своем комментарии к началу, YAML гораздо лучше построен для сериализации и десериализации объектов, потому что он имеет обозначение для него. JSON дает вам ассоциативные массивы или массивы.
Вам нужен JSYNC.
use JSYNC;
use Point;
my $p = Point->new;
$p->X(20);
$p->Y(30);
my $jsync = JSYNC::dump($p, {pretty => 1});
{
"!" : "!perl/hash:Point",
"_x" : "20",
"_y" : "30"
}
Вы пытались прочитать документацию JSON по параметрам allow_blessed и convert_blessed, как указано в сообщении об ошибке? Это должно объяснить, как преобразовать объект Perl в JSON.
Идти другим путем труднее, поскольку JSON не является YAML и не предназначен для десериализации в объектную систему на основе классов, такую как Perl. Вы можете поэкспериментировать с параметрами filter_json_object или filter_json_single_key_object, или вы можете постобработать декодированный JSON и создать объекты самостоятельно.
Может оказаться полезным преобразовать ваши классы в Moose и использовать MooseX::Storage для их сериализации и десериализации.