Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Nyholm opened this issue Mar 4, 2021 · 3 comments
Closed

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

Nyholm opened this issue Mar 4, 2021 · 3 comments

Comments

@Nyholm
Copy link
Member

Nyholm commented Mar 4, 2021

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.

@Nyholm Nyholm added the Bug label Mar 4, 2021
@Nyholm Nyholm changed the title [Serializer] [Serializer] JsonEncoder is not producing enough data to deserialize Mar 4, 2021
@Wirone
Copy link
Contributor

Wirone commented Mar 5, 2021

IMO there is no way to add required data to JSON-serialized structure so deserializer would know about inheritance. This kind of (de)serialization is used e.g. in APIs and clients' won't send such kind of data - and they shouldn't because JSON structure should be fully explicit and deserializable without it ("natively" or with custom DenormalizerInterface implementation).

PS. $fox = new Fox('???'); 😅

@dunglas
Copy link
Member

dunglas commented Jun 24, 2021

Isn't this feature (created by @sroze) covering this use case already? https://symfony.com/doc/current/components/serializer.html#serializing-interfaces-and-abstract-classes

@xabbuh
Copy link
Member

xabbuh commented Jul 10, 2021

Let's close here then.

@xabbuh xabbuh closed this as completed Jul 10, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants