Description
Symfony version(s) affected
7.1.1
Description
This concerns the denormalisation of a nested object using a custom (de)normalizer and COLLECT_DENORMALIZATION_ERRORS=true
.
In Symfony 6.4 & 7.0, when a custom (de)normalizer throws a NotNormalizableValueException
with $useMessageForUser = true
in the denormalize()
function, if Symfony Serializer’s context is set with DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS => true
, it throws a PartialDenormalizationException
and uses message
, path
, and expectedTypes
defined in NotNormalizableValueException::createForUnexpectedDataType()
to inform the user.
In Symfony 7.1, a broader message is generated using the class of the nested object, and loses the valuable information given by the custom normalizer.
Code in a minimalistic Normalizer
public function denormalize(mixed $data, string $type, string $format = null, array $context = []): MySpecialDTO
{
$mySpecialDTO = new MySpecialDTO();
$valueThatNeedsProcessing = $data['key'];
if ('goodValue' !== $valueThatNeedsProcessing) {
// ****************************************************************
// The values & message set here used to be forwarded to client.
// Not anymore on 7.1.
// ****************************************************************
throw NotNormalizableValueException::createForUnexpectedDataType('A clear message for the end user', 'Sample', ['ValidTypeIExpect'], $context['deserialization_path'].'.key', true);
}
$mySpecialDTO->key = $valueThatNeedsProcessing;
return $mySpecialDTO;
}
Symfony 6.4 & 7.0 output, with desired message :
{
"type": "https:\/\/symfony.com\/errors\/validation",
"title": "Validation Failed",
"status": 422,
"detail": "mySpecialField.key: This value should be of type ValidTypeIExpect.",
"violations": [
{
"propertyPath": "mySpecialField.key",
"title": "This value should be of type ValidTypeIExpect.",
"template": "This value should be of type {{ type }}.",
"parameters": {
"{{ type }}": "ValidTypeIExpect"
},
"hint": "A clear message for the end user"
}
]
}
Symfony 7.1 output, with a broader message:
{
"type": "https:\/\/symfony.com\/errors\/validation",
"title": "Validation Failed",
"status": 422,
"detail": "mySpecialField: This value should be of type App\\DTO\\MySpecialDTO|null.",
"violations": [
{
"propertyPath": "mySpecialField",
"title": "This value should be of type App\\DTO\\MySpecialDTO|null.",
"template": "This value should be of type {{ type }}.",
"parameters": {
"{{ type }}": "App\\DTO\\MySpecialDTO|null"
}
}
]
}
How to reproduce
I wrote a simple reproducer, here : https://github.com/yblatti/repro-denorm-error
You'll find relevant code in src/Controller
, src/DTO
and src/Serialization
.
The same code is used, only the Symfony version changes accros 3 branches : sf_6.4, sf_7.0, sf_7.1,
To test on different versions :
git clone https://github.com/yblatti/repro-denorm-error.git
cd repro-denorm-error
# Symfony 6.4
git checkout origin/sf_6.4
composer install
bin/console cache:clear --env=test
bin/phpunit --testdox
# all green results
# Symfony 7.0
git checkout origin/sf_7.0
composer install
bin/console cache:clear --env=test
bin/phpunit --testdox
# all green results
# Symfony 7.1
git checkout origin/sf_7.1
composer install
bin/console cache:clear --env=test
bin/phpunit --testdox
# the second test fails, as the message set in NotNormalizableValueException::createForUnexpectedDataType() is not used
Possible Solution
No response
Additional Context
No response