Search code examples
symfonyrecursionserializationdenormalization

How to denormalize an array recursively in Symfony 5?


I am currently trying to denormalize an array, which came out of an API as a JSON response and was JSON decoded.

The problem is, that I want it to be denormalized into a class and one of the properties is another class.

It feels like it should be possible to get such an easy job done with the Symfony denormalizer, but I always get the following exception:

Failed to denormalize attribute "inner_property" value for class "App\Model\Api\Outer": Expected argument of type "App\Model\Api\Inner", "array" given at property path "inner_property".

My denormalizing code looks like that:

$this->denormalizer->denormalize($jsonOuter, Outer::class);

The denormalizer is injected in the constructor:

public function __construct(DenormalizerInterface $denormalizer) {

The array I try to denormalize:

array (
  'inner_property' => 
  array (
    'property' => '12345',
  ),
)

Finally the both classes I try to denormalize to:

class Outer
{
    /** @var InnerProperty */
    private $innerProperty;

    public function getInnerProperty(): InnerProperty
    {
        return $this->innerProperty;
    }

    public function setInnerProperty(InnerProperty $innerProperty): void
    {
        $this->innerProperty = $innerProperty;
    }
}
class InnerProperty
{
    private $property;

    public function getProperty(): string
    {
        return $this->property;
    }

    public function setProperty(string $property): void
    {
        $this->property = $property;
    }
}

Solution

  • After hours of searching I finally found the reason. The problem was the combination of the "inner_property" snake case and $innerProperty or getInnerProperty camel case. In Symfony 5 the camel case to snake case converter is not enabled by default.

    So I had to do this by adding this config in the config/packages/framework.yaml:

    framework:
            serializer:
                    name_converter: 'serializer.name_converter.camel_case_to_snake_case'
    

    Here is the reference to the Symfony documentation: https://symfony.com/doc/current/serializer.html#enabling-a-name-converter

    Alternatively I could have also add a SerializedName annotation to the property in the Outer class: https://symfony.com/doc/current/components/serializer.html#configure-name-conversion-using-metadata

    PS: My question was not asked properly, because I didn't changed the property and class names properly. So I fixed that in the question for future visitors.