Skip to content

Commit 1b2ab75

Browse files
bug symfony#46765 [Serializer] Fix denormalization union types with constructor (Gwemox)
This PR was merged into the 4.4 branch. Discussion ---------- [Serializer] Fix denormalization union types with constructor | Q | A | ------------- | --- | Branch? | 4.4 | Bug fix? | yes | New feature? | no | Deprecations? | no | Tickets | Fix symfony#46396 | License | MIT Fix bug when deserialize union types with constructor. Before that, `MissingConstructorArgumentsException` was thrown even if another type matched. Is similar to symfony#45861 Commits ------- 33fb153 [Serializer] Fix denormalization union types with constructor
2 parents 45db39c + 33fb153 commit 1b2ab75

File tree

2 files changed

+40
-8
lines changed

2 files changed

+40
-8
lines changed

src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use Symfony\Component\Serializer\Encoder\XmlEncoder;
2121
use Symfony\Component\Serializer\Exception\ExtraAttributesException;
2222
use Symfony\Component\Serializer\Exception\LogicException;
23+
use Symfony\Component\Serializer\Exception\MissingConstructorArgumentsException;
2324
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
2425
use Symfony\Component\Serializer\Exception\RuntimeException;
2526
use Symfony\Component\Serializer\Mapping\AttributeMetadataInterface;
@@ -395,6 +396,8 @@ abstract protected function setAttributeValue($object, $attribute, $value, $form
395396
* @return mixed
396397
*
397398
* @throws NotNormalizableValueException
399+
* @throws ExtraAttributesException
400+
* @throws MissingConstructorArgumentsException
398401
* @throws LogicException
399402
*/
400403
private function validateAndDenormalize(string $currentClass, string $attribute, $data, ?string $format, array $context)
@@ -406,6 +409,7 @@ private function validateAndDenormalize(string $currentClass, string $attribute,
406409
$expectedTypes = [];
407410
$isUnionType = \count($types) > 1;
408411
$extraAttributesException = null;
412+
$missingConstructorArgumentException = null;
409413
foreach ($types as $type) {
410414
if (null === $data && $type->isNullable()) {
411415
return null;
@@ -503,13 +507,25 @@ private function validateAndDenormalize(string $currentClass, string $attribute,
503507
if (!$extraAttributesException) {
504508
$extraAttributesException = $e;
505509
}
510+
} catch (MissingConstructorArgumentsException $e) {
511+
if (!$isUnionType) {
512+
throw $e;
513+
}
514+
515+
if (!$missingConstructorArgumentException) {
516+
$missingConstructorArgumentException = $e;
517+
}
506518
}
507519
}
508520

509521
if ($extraAttributesException) {
510522
throw $extraAttributesException;
511523
}
512524

525+
if ($missingConstructorArgumentException) {
526+
throw $missingConstructorArgumentException;
527+
}
528+
513529
if ($context[self::DISABLE_TYPE_ENFORCEMENT] ?? $this->defaultContext[self::DISABLE_TYPE_ENFORCEMENT] ?? false) {
514530
return $data;
515531
}

src/Symfony/Component/Serializer/Tests/SerializerTest.php

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -586,20 +586,26 @@ public function testUnionTypeDeserializableWithoutAllowedExtraAttributes()
586586
['json' => new JsonEncoder()]
587587
);
588588

589-
$actual = $serializer->deserialize('{ "v": { "a": 0 }}', DummyUnionWithAAndB::class, 'json', [
589+
$actual = $serializer->deserialize('{ "v": { "a": 0 }}', DummyUnionWithAAndCAndB::class, 'json', [
590590
AbstractNormalizer::ALLOW_EXTRA_ATTRIBUTES => false,
591591
]);
592592

593-
$this->assertEquals(new DummyUnionWithAAndB(new DummyATypeForUnion()), $actual);
593+
$this->assertEquals(new DummyUnionWithAAndCAndB(new DummyATypeForUnion()), $actual);
594594

595-
$actual = $serializer->deserialize('{ "v": { "b": 1 }}', DummyUnionWithAAndB::class, 'json', [
595+
$actual = $serializer->deserialize('{ "v": { "b": 1 }}', DummyUnionWithAAndCAndB::class, 'json', [
596596
AbstractNormalizer::ALLOW_EXTRA_ATTRIBUTES => false,
597597
]);
598598

599-
$this->assertEquals(new DummyUnionWithAAndB(new DummyBTypeForUnion()), $actual);
599+
$this->assertEquals(new DummyUnionWithAAndCAndB(new DummyBTypeForUnion()), $actual);
600+
601+
$actual = $serializer->deserialize('{ "v": { "c": 3 }}', DummyUnionWithAAndCAndB::class, 'json', [
602+
AbstractNormalizer::ALLOW_EXTRA_ATTRIBUTES => false,
603+
]);
604+
605+
$this->assertEquals(new DummyUnionWithAAndCAndB(new DummyCTypeForUnion(3)), $actual);
600606

601607
$this->expectException(ExtraAttributesException::class);
602-
$serializer->deserialize('{ "v": { "b": 1, "c": "i am not allowed" }}', DummyUnionWithAAndB::class, 'json', [
608+
$serializer->deserialize('{ "v": { "b": 1, "d": "i am not allowed" }}', DummyUnionWithAAndCAndB::class, 'json', [
603609
AbstractNormalizer::ALLOW_EXTRA_ATTRIBUTES => false,
604610
]);
605611
}
@@ -719,13 +725,23 @@ class DummyBTypeForUnion
719725
public $b = 1;
720726
}
721727

722-
class DummyUnionWithAAndB
728+
class DummyCTypeForUnion
729+
{
730+
public $c = 2;
731+
732+
public function __construct($c)
733+
{
734+
$this->c = $c;
735+
}
736+
}
737+
738+
class DummyUnionWithAAndCAndB
723739
{
724-
/** @var DummyATypeForUnion|DummyBTypeForUnion */
740+
/** @var DummyATypeForUnion|DummyCTypeForUnion|DummyBTypeForUnion */
725741
public $v;
726742

727743
/**
728-
* @param DummyATypeForUnion|DummyBTypeForUnion $v
744+
* @param DummyATypeForUnion|DummyCTypeForUnion|DummyBTypeForUnion $v
729745
*/
730746
public function __construct($v)
731747
{

0 commit comments

Comments
 (0)