diff --git a/Normalizer/AbstractObjectNormalizer.php b/Normalizer/AbstractObjectNormalizer.php index c235e471a..9c6098b5f 100644 --- a/Normalizer/AbstractObjectNormalizer.php +++ b/Normalizer/AbstractObjectNormalizer.php @@ -190,12 +190,7 @@ public function normalize(mixed $object, string $format = null, array $context = $attributeValue = $attribute === $this->classDiscriminatorResolver?->getMappingForMappedObject($object)?->getTypeProperty() ? $this->classDiscriminatorResolver?->getTypeForMappedObject($object) : $this->getAttributeValue($object, $attribute, $format, $attributeContext); - } catch (UninitializedPropertyException $e) { - if ($context[self::SKIP_UNINITIALIZED_VALUES] ?? $this->defaultContext[self::SKIP_UNINITIALIZED_VALUES] ?? true) { - continue; - } - throw $e; - } catch (\Error $e) { + } catch (UninitializedPropertyException|\Error $e) { if (($context[self::SKIP_UNINITIALIZED_VALUES] ?? $this->defaultContext[self::SKIP_UNINITIALIZED_VALUES] ?? true) && $this->isUninitializedValueError($e)) { continue; } @@ -373,6 +368,10 @@ public function denormalize(mixed $data, string $type, string $format = null, ar ? $discriminatorMapping : $this->getAttributeValue($object, $attribute, $format, $attributeContext); } catch (NoSuchPropertyException) { + } catch (UninitializedPropertyException|\Error $e) { + if (!(($context[self::SKIP_UNINITIALIZED_VALUES] ?? $this->defaultContext[self::SKIP_UNINITIALIZED_VALUES] ?? true) && $this->isUninitializedValueError($e))) { + throw $e; + } } } @@ -769,9 +768,10 @@ private function getCacheKey(?string $format, array $context): bool|string * This error may occur when specific object normalizer implementation gets attribute value * by accessing a public uninitialized property or by calling a method accessing such property. */ - private function isUninitializedValueError(\Error $e): bool + private function isUninitializedValueError(\Error|UninitializedPropertyException $e): bool { - return str_starts_with($e->getMessage(), 'Typed property') + return $e instanceof UninitializedPropertyException + || str_starts_with($e->getMessage(), 'Typed property') && str_ends_with($e->getMessage(), 'must not be accessed before initialization'); } diff --git a/Tests/Normalizer/Features/SkipUninitializedValuesTestTrait.php b/Tests/Normalizer/Features/SkipUninitializedValuesTestTrait.php index fb055abd1..dfcb904ab 100644 --- a/Tests/Normalizer/Features/SkipUninitializedValuesTestTrait.php +++ b/Tests/Normalizer/Features/SkipUninitializedValuesTestTrait.php @@ -12,14 +12,14 @@ namespace Symfony\Component\Serializer\Tests\Normalizer\Features; use Symfony\Component\PropertyAccess\Exception\UninitializedPropertyException; -use Symfony\Component\Serializer\Normalizer\NormalizerInterface; +use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer; /** * Test AbstractObjectNormalizer::SKIP_UNINITIALIZED_VALUES. */ trait SkipUninitializedValuesTestTrait { - abstract protected function getNormalizerForSkipUninitializedValues(): NormalizerInterface; + abstract protected function getNormalizerForSkipUninitializedValues(): AbstractObjectNormalizer; /** * @dataProvider skipUninitializedValuesFlagProvider @@ -31,6 +31,15 @@ public function testSkipUninitializedValues(array $context) $normalizer = $this->getNormalizerForSkipUninitializedValues(); $result = $normalizer->normalize($object, null, $context); $this->assertSame(['initialized' => 'value'], $result); + + $normalizer->denormalize( + ['unInitialized' => 'value'], + TypedPropertiesObjectWithGetters::class, + null, + ['object_to_populate' => $objectToPopulate = new TypedPropertiesObjectWithGetters(), 'deep_object_to_populate' => true] + $context + ); + + $this->assertSame('value', $objectToPopulate->getUninitialized()); } public function skipUninitializedValuesFlagProvider(): iterable diff --git a/Tests/Normalizer/GetSetMethodNormalizerTest.php b/Tests/Normalizer/GetSetMethodNormalizerTest.php index 1d471981e..7877a3c5e 100644 --- a/Tests/Normalizer/GetSetMethodNormalizerTest.php +++ b/Tests/Normalizer/GetSetMethodNormalizerTest.php @@ -487,7 +487,7 @@ protected function getNormalizerForCacheableObjectAttributesTest(): GetSetMethod return new GetSetMethodNormalizer(); } - protected function getNormalizerForSkipUninitializedValues(): NormalizerInterface + protected function getNormalizerForSkipUninitializedValues(): GetSetMethodNormalizer { return new GetSetMethodNormalizer(new ClassMetadataFactory(new AttributeLoader())); } diff --git a/Tests/Normalizer/PropertyNormalizerTest.php b/Tests/Normalizer/PropertyNormalizerTest.php index 631111d2a..0601a2d60 100644 --- a/Tests/Normalizer/PropertyNormalizerTest.php +++ b/Tests/Normalizer/PropertyNormalizerTest.php @@ -25,7 +25,6 @@ use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer; use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer; use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; -use Symfony\Component\Serializer\Normalizer\NormalizerInterface; use Symfony\Component\Serializer\Normalizer\PropertyNormalizer; use Symfony\Component\Serializer\Serializer; use Symfony\Component\Serializer\SerializerInterface; @@ -492,7 +491,7 @@ protected function getNormalizerForCacheableObjectAttributesTest(): AbstractObje return new PropertyNormalizer(); } - protected function getNormalizerForSkipUninitializedValues(): NormalizerInterface + protected function getNormalizerForSkipUninitializedValues(): PropertyNormalizer { return new PropertyNormalizer(new ClassMetadataFactory(new AttributeLoader())); }