Skip to content

[Serializer] PropertyNormalizer doesn't support DiscriminatorMap #36585

@agven

Description

@agven

Symfony version(s) affected: 4.4.7 (probably lower and higher also)

Description

Could someone explain me why PropertyNormalizer doesn't support DiscriminatorMap ?

Everything works fine if I use ObjectNormalizer but if I choose PropertyNormalizer instead of ObjectNormalizer and do serialization or desialization as a result this functionality doesn't work. However both normalizers have one common parent class this is AbstractObjectNormalizer and if you look at the constructor declaration you will see a dependency on ClassDiscriminatorResolverInterface but PropertyNormalizer doesn't support a "discriminator class mapping".

As seems to me something is wrong with Barbora-Liskov substitution principle. Am I right, or were there reasons for that ?

How to reproduce

// ...
use Doctrine\Common\Annotations\AnnotationReader;
use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorFromClassMetadata;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
use Symfony\Component\Serializer\Normalizer\PropertyNormalizer;
use Symfony\Component\Serializer\Serializer;

/**
 * @DiscriminatorMap(typeProperty="type", mapping={
 *    "github"="GitHubCodeRepository",
 *    "bitbucket"="BitBucketCodeRepository"
 * })
 */
interface CodeRepository {}

class GitHubCodeRepository implements CodeRepository 
{
    private $url;
}

class BitBucketCodeRepository implements CodeRepository 
{
    private $url;
}

$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
$discriminator = new ClassDiscriminatorFromClassMetadata($classMetadataFactory);

$serializer = new Serializer(
    [new PropertyNormalizer($classMetadataFactory, null, null, $discriminator)],
    ['json' => new JsonEncoder()]
);

$serialized = $serializer->serialize(new GitHubCodeRepository(), 'json');
// actual: {"type":null, "url":"null"}
// expected: {"type":"github"}

$repository = $serializer->deserialize($serialized, CodeRepository::class, 'json');
// actual:
//     exception: \Symfony\Component\Serializer\Exception\NotNormalizableValueException
//     message: Could not denormalize object of type "CodeRepository", no supporting normalizer found.

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