diff --git a/Normalizer/AbstractObjectNormalizer.php b/Normalizer/AbstractObjectNormalizer.php index 0ba9272a2..d43cbbbdd 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 ccbb7be0e..2f61ceb67 100644 --- a/Tests/Normalizer/GetSetMethodNormalizerTest.php +++ b/Tests/Normalizer/GetSetMethodNormalizerTest.php @@ -493,7 +493,7 @@ protected function getNormalizerForCacheableObjectAttributesTest(): GetSetMethod return new GetSetMethodNormalizer(); } - protected function getNormalizerForSkipUninitializedValues(): NormalizerInterface + protected function getNormalizerForSkipUninitializedValues(): GetSetMethodNormalizer { return new GetSetMethodNormalizer(new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()))); } diff --git a/Tests/Normalizer/PropertyNormalizerTest.php b/Tests/Normalizer/PropertyNormalizerTest.php index 915622f2f..e7eff114f 100644 --- a/Tests/Normalizer/PropertyNormalizerTest.php +++ b/Tests/Normalizer/PropertyNormalizerTest.php @@ -26,7 +26,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; @@ -500,7 +499,7 @@ protected function getNormalizerForCacheableObjectAttributesTest(): AbstractObje return new PropertyNormalizer(); } - protected function getNormalizerForSkipUninitializedValues(): NormalizerInterface + protected function getNormalizerForSkipUninitializedValues(): PropertyNormalizer { return new PropertyNormalizer(new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()))); }