Подтвердить что ты не робот

Как преобразовать объекты 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?

4b9b3361

Ответ 1

Предупреждение сообщает вам больше всего, что не так. Если вы не сообщите JSON, как обращаться с блаженными ссылками (объекты Perl), JSON обрабатывает только неработающие структуры данных.

Вы можете convert_blessed, и вы можете allow_blessed. Для allow_blessed говорится:

Если $enable является ложным (по умолчанию), тогда кодирование выдает исключение, когда оно встречает благословенный объект.

Точка - это класс объекта, поэтому экземпляр 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 предоставляет ассоциативные массивы или массивы.

Ответ 2

Пробовал ли вы читать документацию JSON на allow_blessed и convert_blessed, как это было предложено сообщением об ошибке? Это должно объяснить, как преобразовать объект Perl в JSON.

Переход на другой путь сложнее, поскольку JSON не YAML и не был предназначен для десериализации в класс- основанной на объектах, такой как Perl. Вы можете экспериментировать с filter_json_object или filter_json_single_key_object параметры, или вы могли бы обработать декодированный JSON и создать объекты самостоятельно.

Ответ 3

Вам нужно 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"
}

Ответ 4

Вы можете счесть полезным преобразовать свои классы в Moose и использовать MooseX:: Storage для сериализации и десериализации.