Skip to content
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

symfony/serializer version 7.0.7 now throws NotNormalizableValueException #54784

Closed
verfriemelt-dot-org opened this issue Apr 30, 2024 · 5 comments

Comments

@verfriemelt-dot-org
Copy link
Contributor

Symfony version(s) affected

7.0.7

Description

i inherited the following code, and now i am unsure wether this is a bug in the last patch-release or a bug in my code. up until version 7.0.6 it worked just fine so far.

How to reproduce

<?xml version="1.0" encoding="UTF-8"?>
<Trias>
    <ServiceDelivery>
        <DeliveryPayload>
            <TripResponse>
                <foo />
                <foo />
            </TripResponse>
        </DeliveryPayload>
    </ServiceDelivery>
</Trias>

with the following DTOs

final class Trias
{
    private ?ServiceDeliveryStructure $serviceDelivery = null;

    /**
     * @return ServiceDeliveryStructure
     */
    public function getServiceDelivery()
    {
        return $this->serviceDelivery;
    }

    public function setServiceDelivery(ServiceDeliveryStructure $serviceDelivery): void
    {
        $this->serviceDelivery = $serviceDelivery;
    }
}
final class ServiceDeliveryStructure
{
    private ?DeliveryPayloadStructure $deliveryPayload = null;

    /**
     * @return DeliveryPayloadStructure
     */
    public function getDeliveryPayload()
    {
        return $this->deliveryPayload;
    }

    public function setDeliveryPayload(DeliveryPayloadStructure $deliveryPayload): void
    {
        $this->deliveryPayload = $deliveryPayload;
    }
}
final class DeliveryPayloadStructure
{
    private ?TripResponse $tripResponse = null;

    /**
     * @return TripResponse
     */
    public function getTripResponse()
    {
        return $this->tripResponse;
    }

    public function setTripResponse(TripResponse $tripResponse): void
    {
        $this->tripResponse = $tripResponse;
    }
}

starting with version 7.0.7 i'll get the following error:

Symfony\Component\Serializer\Exception\NotNormalizableValueException: The type of the "tripResponse" attribute for class "EosUptrade\FIS\TRIAS\Dto\DeliveryPayloadStructure" must be one of "EosUptrade\FIS\TRIAS\Dto\TripResponse" ("array" given).

when calling

$serializer->deserialize($content, Trias::class, XmlEncoder::FORMAT);

with the following service configuration:

    $services->set('trias.name_converter', UppercaseFirstLetterNameConverter::class);
    $services->set('trias.property_type_extractor', PhpDocExtractor::class);

    $services
        ->set('trias.get_set_method_normalizer', GetSetMethodNormalizer::class)
        ->args([
            null,
            service('trias.name_converter'),
            service('trias.property_type_extractor'),
        ]);

    $services->set('trias.array_denormalizer', ArrayDenormalizer::class);
    $services->set('trias.xml_encoder', XmlEncoder::class);

    $services
        ->set('trias.serializer', Serializer::class)
        ->public()
        ->args([
            [
                service('trias.get_set_method_normalizer'),
                service('trias.array_denormalizer'),
            ],
            [service('trias.xml_encoder')],
        ]);

Possible Solution

No response

Additional Context

No response

@xabbuh
Copy link
Member

xabbuh commented Apr 30, 2024

What does your TripResponse class look like?

@verfriemelt-dot-org
Copy link
Contributor Author

here you go:

final class TripResponse
{
    /** @var ErrorMessageStructure[]|null */
    private ?array $errorMessage = null;

    private ?TripResponseContextStructure $tripResponseContext = null;

    /** @var TripResultStructure[]|null */
    private ?array $tripResult = null;

    public function hasErrorMessage(): bool
    {
        return !empty($this->errorMessage);
    }

    /**
     * @return ErrorMessageStructure[]
     */
    public function getErrorMessage()
    {
        return $this->errorMessage;
    }

    /**
     * @param ErrorMessageStructure[] $errorMessage
     */
    public function setErrorMessage(?array $errorMessage = null): void
    {
        $this->errorMessage = $errorMessage;
    }

    /**
     * @return TripResponseContextStructure
     */
    public function getTripResponseContext()
    {
        return $this->tripResponseContext;
    }

    public function setTripResponseContext(?TripResponseContextStructure $tripResponseContext = null): void
    {
        $this->tripResponseContext = $tripResponseContext;
    }

    /**
     * @return TripResultStructure[]
     */
    public function getTripResult()
    {
        return $this->tripResult;
    }

    /**
     * @param TripResultStructure[] $tripResult
     */
    public function setTripResult(?array $tripResult = null): void
    {
        $this->tripResult = $tripResult;
    }
}

from there on the XML input ongoing like this:

            <TripResponse>
                <TripResponseContext>
                    <Situations/>
                </TripResponseContext>
                <TripResult>[...]<TripResult>
                <TripResult>[...]<TripResult>
                <TripResult>[...]<TripResult>
                <TripResult>[...]<TripResult>
            </TripResponse>

thank you already for your help :)

@xabbuh
Copy link
Member

xabbuh commented Apr 30, 2024

I don't get this error. Maybe there is something more missing from your application to reproduce this.

Can you please create a small example application that allows to reproduce it?

@verfriemelt-dot-org
Copy link
Contributor Author

i created a little poc here to illustrate the issue:

https://github.com/verfriemelt-dot-org/serializer-poc

$ composer install 2>/dev/null
$ vendor/bin/phpunit
PHPUnit 11.1.3 by Sebastian Bergmann and contributors.

Runtime:       PHP 8.3.6
Configuration: /home/easteregg/src/serialize-poc/phpunit.xml

E                                                                   1 / 1 (100%)

Time: 00:00.114, Memory: 6.00 MB

There was 1 error:

1) Test::test
Symfony\Component\Serializer\Exception\NotNormalizableValueException: The type of the "tripResponse" attribute for class "Dto\DeliveryPayloadStructure" must be one of "Dto\TripResponse" ("array" given).

/home/easteregg/src/serialize-poc/vendor/symfony/serializer/Exception/NotNormalizableValueException.php:32
/home/easteregg/src/serialize-poc/vendor/symfony/serializer/Normalizer/AbstractObjectNormalizer.php:597
/home/easteregg/src/serialize-poc/vendor/symfony/serializer/Normalizer/AbstractObjectNormalizer.php:366
/home/easteregg/src/serialize-poc/vendor/symfony/serializer/Serializer.php:238
/home/easteregg/src/serialize-poc/vendor/symfony/serializer/Normalizer/AbstractObjectNormalizer.php:537
/home/easteregg/src/serialize-poc/vendor/symfony/serializer/Normalizer/AbstractObjectNormalizer.php:366
/home/easteregg/src/serialize-poc/vendor/symfony/serializer/Serializer.php:238
/home/easteregg/src/serialize-poc/vendor/symfony/serializer/Normalizer/AbstractObjectNormalizer.php:537
/home/easteregg/src/serialize-poc/vendor/symfony/serializer/Normalizer/AbstractObjectNormalizer.php:366
/home/easteregg/src/serialize-poc/vendor/symfony/serializer/Serializer.php:238
/home/easteregg/src/serialize-poc/vendor/symfony/serializer/Serializer.php:143
/home/easteregg/src/serialize-poc/poc/Test.php:51

ERRORS!
Tests: 1, Assertions: 0, Errors: 1.

where as if you require 7.0.6 it works:

$ composer require symfony/serializer:7.0.6 2>/dev/null
$ vendor/bin/phpunit
PHPUnit 11.1.3 by Sebastian Bergmann and contributors.

Runtime:       PHP 8.3.6
Configuration: /home/easteregg/src/serialize-poc/phpunit.xml

.                                                                   1 / 1 (100%)

Time: 00:00.103, Memory: 6.00 MB

OK (1 test, 0 assertions)

this example is as small as i could create it, hope that helps 🤔

@HypeMC
Copy link
Contributor

HypeMC commented May 1, 2024

The problem was introduced in #52917. Previously, only the isGetMethod() method existed, and it returned true. However, for denormalization, the new isSetMethod() method is now used, which returns false. This occurs because it expects the number of required arguments to be exactly one, but your setter has an optional argument: setTripResult(?array $tripResult = null).

IMO, a setter should have at least one argument, maybe more, and it shouldn't matter if it's required or not.

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

4 participants