Skip to content

Inconsistent behaviour when deserializing json with snake_case properties #61054

Open
@MariusJam

Description

@MariusJam

Symfony version(s) affected

7.3.1

Description

Hello,

When deserializing a json document with properties written in snake_case, the behaviour seems inconsistent depending on the property visibility and the use of getters/setters or hooks.

  • public properties are not deserialized
  • private properties with getters / setters are deserialized
  • private properties with hook are not deserialized

How to reproduce

Given this class which is the deserialization target:

namespace App\Model;

class TestDeserialize {
    public string $publicKey = "";
    private string $privateKey = "";

    private string $hookedKey = "" {
        get => $this->hookedKey;
        set => $this->hookedKey = $value;
    }

    public function getPrivateKey(): string
    {
        return $this->privateKey;
    }

    public function setPrivateKey(string $privateKey): void
    {
        $this->privateKey = $privateKey;
    }
}

Below is a command which reproduce the issue:

<?php

namespace App\Command;

use App\Model\TestDeserialize;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Serializer\SerializerInterface;

#[AsCommand(
    name: 'test:deserialize',
    description: 'Add a short description for your command',
)]
class TestSerialCommand extends Command
{
    private const string JSON =
        <<<JSON
        {
          "public_key": "foo",
          "private_key": "bar",
          "hooked_key": "fuz" 
        }
        JSON;


    public function __construct(private readonly SerializerInterface $serializer)
    {
        parent::__construct();
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        dump($this->serializer->deserialize(self::JSON, TestDeserialize::class, 'json'));
        return Command::SUCCESS;
    }
}

In the dump, we can see the inconsistency of the result:

App\Model\TestDeserialize^ {#1016
  +publicKey: ""
  -privateKey: "bar"
  -hookedKey: ""
}

Possible Solution

No response

Additional Context

I have been able to track down the issue to \Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor::isWritable() (which is called by \Symfony\Component\Serializer\Normalizer\ObjectNormalizer::isAllowedAttribute()). In the following lines, a reflectionMethod will be found for a private property with a setter method, whereas it will return null in other cases.

// First test with the camelized property name
        [$reflectionMethod] = $this->getMutatorMethod($class, $this->camelize($property));
        if (null !== $reflectionMethod) {
            return true;
        }

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

      pFad - Phonifier reborn

      Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

      Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


      Alternative Proxies:

      Alternative Proxy

      pFad Proxy

      pFad v3 Proxy

      pFad v4 Proxy