Skip to content

Commit a9a4b0c

Browse files
committed
Handle ObjectConstructor returning NULL
The DeserializationGraphNavigator calls the construct method on an instance of ObjectConstructorInterface. According to the return type hint of that method, it is allowed to return NULL. However, when this occurs, the navigator will pass NULL to the startVisitingObject method of the visitor. startVisitingObject expects an object to be passed in, thus causing the serializer to crash with a type error. We can prevent this error by calling the `visitNull` method if we detect that the ObjectConstructor has returned NULL instead of an object.
1 parent 25a829b commit a9a4b0c

2 files changed

Lines changed: 21 additions & 0 deletions

File tree

src/GraphNavigator/DeserializationGraphNavigator.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,13 @@ public function accept($data, ?array $type = null)
184184

185185
$object = $this->objectConstructor->construct($this->visitor, $metadata, $data, $type, $this->context);
186186

187+
if (null === $object) {
188+
$this->context->popClassMetadata();
189+
$this->context->decreaseDepth();
190+
191+
return $this->visitor->visitNull($data, $type);
192+
}
193+
187194
$this->visitor->startVisitingObject($metadata, $object, $type);
188195
foreach ($metadata->propertyMetadata as $propertyMetadata) {
189196
if (null !== $this->exclusionStrategy && $this->exclusionStrategy->shouldSkipProperty($propertyMetadata, $this->context)) {

tests/Serializer/GraphNavigatorTest.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use Doctrine\Common\Annotations\AnnotationReader;
88
use JMS\Serializer\Accessor\DefaultAccessorStrategy;
9+
use JMS\Serializer\Construction\ObjectConstructorInterface;
910
use JMS\Serializer\Construction\UnserializeObjectConstructor;
1011
use JMS\Serializer\DeserializationContext;
1112
use JMS\Serializer\EventDispatcher\EventDispatcher;
@@ -156,6 +157,19 @@ public function testExposeAcceptHandlerExceptionOnSerialization()
156157
$navigator->accept($object, ['name' => $typeName, 'params' => []]);
157158
}
158159

160+
/**
161+
* @doesNotPerformAssertions
162+
*/
163+
public function testNavigatorDoesNotCrashWhenObjectConstructorReturnsNull()
164+
{
165+
$objectConstructor = $this->getMockBuilder(ObjectConstructorInterface::class)->getMock();
166+
$objectConstructor->method('construct')->willReturn(null);
167+
$navigator = new DeserializationGraphNavigator($this->metadataFactory, $this->handlerRegistry, $objectConstructor, $this->accessor, $this->dispatcher);
168+
$navigator->initialize($this->deserializationVisitor, $this->deserializationContext);
169+
170+
$navigator->accept(['id' => 1234], ['name' => SerializableClass::class]);
171+
}
172+
159173
protected function setUp(): void
160174
{
161175
$this->deserializationVisitor = $this->getMockBuilder(DeserializationVisitorInterface::class)->getMock();

0 commit comments

Comments
 (0)