Skip to content

[Serializer] JsonEncoder is not producing enough data to deserialize #40359

Closed
@Nyholm

Description

@Nyholm

Symfony version(s) affected: 5.x and most likely earlier versions

Description
The Serializer::serialize() with JsonEncoder don't care about child classes which causes issues when deserializing. See #33394

How to reproduce

<?php

use Symfony\Component\PropertyAccess\PropertyAccessor;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Normalizer\UnwrappingDenormalizer;
use Symfony\Component\Serializer\Serializer;

require __DIR__.'/vendor/autoload.php';

class Animal
{
    private $sound;

    public function __construct($sound)
    {
        $this->sound = $sound;
    }

    public function __toString(): string
    {
        return (string) $this->sound;
    }

    /**
     * Without this method, the "deserialize()" will fail with:
     * > Fatal error: Uncaught Symfony\Component\Serializer\Exception\MissingConstructorArgumentsException:
     * > Cannot create an instance of "Animal" from serialized data because its
     * > constructor requires parameter "sound" to be present.
     */
    public function getSound()
    {
        return $this->sound;
    }
}

class Fox extends Animal
{
    private $color;
    private $name;

    public function getColor()
    {
        return $this->color;
    }

    public function setColor($color): void
    {
        $this->color = $color;
    }

    public function getName()
    {
        return $this->name;
    }

    public function setName($name): void
    {
        $this->name = $name;
    }
}

class Wrapper
{
    private $animal;

    public function __construct(Animal $animal)
    {
        $this->animal = $animal;
    }

    public function getAnimal(): Animal
    {
        return $this->animal;
    }
}

$serializer = new Serializer([new UnwrappingDenormalizer(new PropertyAccessor()), new ObjectNormalizer()], ['json' => new JsonEncoder()]);

$fox = new Fox('???');
$fox->setName('Foobar');
$fox->setColor('Red');

$data = $serializer->serialize(new Wrapper($fox), 'json');
var_dump($data);

$result = $serializer->deserialize($data, Wrapper::class, 'json');
var_dump($result);
 php test.php
string(56) "{"animal":{"color":"Red","name":"Foobar","sound":"???"}}"
object(Wrapper)#32 (1) {
  ["animal":"Wrapper":private]=>
  object(Animal)#38 (1) {
    ["sound":"Animal":private]=>
    string(3) "???"
  }
}

The wrapper should contain a Fox, not an Animal.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions