Skip to content

Commit

Permalink
bug #45861 [Serializer] Try all possible denormalization route with u…
Browse files Browse the repository at this point in the history
…nion types when ALLOW_EXTRA_ATTRIBUTES=false (T-bond)

This PR was squashed before being merged into the 4.4 branch.

Discussion
----------

[Serializer] Try all possible denormalization route with union types when ALLOW_EXTRA_ATTRIBUTES=false

| Q             | A
| ------------- | ---
| Branch?       | 4.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | #45860
| License       | MIT
| Doc PR        | -

I found a similar bug, (I think this is a bug, but it is possible, it is an intended behaviour) to my previous report.

Commits
-------

bd623b9 [Serializer] Try all possible denormalization route with union types when ALLOW_EXTRA_ATTRIBUTES=false
  • Loading branch information
nicolas-grekas committed Jun 19, 2022
2 parents af45ea5 + bd623b9 commit 0523bd3
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ public function denormalize($data, $type, $format = null, array $context = [])
}
}

if (!empty($extraAttributes)) {
if ($extraAttributes) {
throw new ExtraAttributesException($extraAttributes);
}

Expand Down Expand Up @@ -405,6 +405,7 @@ private function validateAndDenormalize(string $currentClass, string $attribute,

$expectedTypes = [];
$isUnionType = \count($types) > 1;
$extraAttributesException = null;
foreach ($types as $type) {
if (null === $data && $type->isNullable()) {
return null;
Expand Down Expand Up @@ -494,9 +495,21 @@ private function validateAndDenormalize(string $currentClass, string $attribute,
if (!$isUnionType) {
throw $e;
}
} catch (ExtraAttributesException $e) {
if (!$isUnionType) {
throw $e;
}

if (!$extraAttributesException) {
$extraAttributesException = $e;
}
}
}

if ($extraAttributesException) {
throw $extraAttributesException;
}

if ($context[self::DISABLE_TYPE_ENFORCEMENT] ?? $this->defaultContext[self::DISABLE_TYPE_ENFORCEMENT] ?? false) {
return $data;
}
Expand Down
55 changes: 55 additions & 0 deletions src/Symfony/Component/Serializer/Tests/SerializerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use Symfony\Component\Serializer\Encoder\DecoderInterface;
use Symfony\Component\Serializer\Encoder\EncoderInterface;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Exception\ExtraAttributesException;
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
use Symfony\Component\Serializer\Exception\LogicException;
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
Expand All @@ -31,6 +32,7 @@
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer;
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;
use Symfony\Component\Serializer\Normalizer\CustomNormalizer;
Expand Down Expand Up @@ -573,6 +575,35 @@ public function testUnionTypeDeserializable()
$this->assertEquals(new DummyUnionType(), $actual, 'Union type denormalization third case failed.');
}

public function testUnionTypeDeserializableWithoutAllowedExtraAttributes()
{
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
$extractor = new PropertyInfoExtractor([], [new PhpDocExtractor(), new ReflectionExtractor()]);
$serializer = new Serializer(
[
new ObjectNormalizer($classMetadataFactory, null, null, $extractor, new ClassDiscriminatorFromClassMetadata($classMetadataFactory)),
],
['json' => new JsonEncoder()]
);

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

$this->assertEquals(new DummyUnionWithAAndB(new DummyATypeForUnion()), $actual);

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

$this->assertEquals(new DummyUnionWithAAndB(new DummyBTypeForUnion()), $actual);

$this->expectException(ExtraAttributesException::class);
$serializer->deserialize('{ "v": { "b": 1, "c": "i am not allowed" }}', DummyUnionWithAAndB::class, 'json', [
AbstractNormalizer::ALLOW_EXTRA_ATTRIBUTES => false,
]);
}

/**
* @requires PHP 8.2
*/
Expand Down Expand Up @@ -678,6 +709,30 @@ public function setChanged($changed): self
}
}

class DummyATypeForUnion
{
public $a = 0;
}

class DummyBTypeForUnion
{
public $b = 1;
}

class DummyUnionWithAAndB
{
/** @var DummyATypeForUnion|DummyBTypeForUnion */
public $v;

/**
* @param DummyATypeForUnion|DummyBTypeForUnion $v
*/
public function __construct($v)
{
$this->v = $v;
}
}

interface NormalizerAwareNormalizer extends NormalizerInterface, NormalizerAwareInterface
{
}
Expand Down

0 comments on commit 0523bd3

Please sign in to comment.