Skip to content

Commit

Permalink
Merge pull request #790 from schmittjoh/webservices-nl-fix-xml-nil-de…
Browse files Browse the repository at this point in the history
…serialization

Detect XML xsi:nil="true" to null when deserializing
  • Loading branch information
goetas authored Jun 24, 2017
2 parents b57ee1e + f31243f commit 3617f8d
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 2 deletions.
1 change: 0 additions & 1 deletion src/AbstractVisitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,4 @@ protected function getElementType($typeArray)
return $typeArray['params'][0];
}
}

}
5 changes: 5 additions & 0 deletions src/GraphNavigator.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,11 @@ public function accept($data, array $type = null, Context $context)
else if ($context instanceof SerializationContext && null === $data) {
$type = array('name' => 'NULL', 'params' => array());
}
// Sometimes data can convey null but is not of a null type.
// Visitors can have the power to add this custom null evaluation
if ($visitor instanceof NullAwareVisitorInterface && $visitor->isNull($data) === true) {
$type = array('name' => 'NULL', 'params' => array());
}

switch ($type['name']) {
case 'NULL':
Expand Down
32 changes: 32 additions & 0 deletions src/NullAwareVisitorInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

/*
* Copyright 2016 Johannes M. Schmitt <[email protected]>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

namespace JMS\Serializer;

interface NullAwareVisitorInterface extends VisitorInterface
{
/**
* Determine if a value conveys a null value.
* An example could be an xml element (Dom, SimpleXml, ...) that is tagged with a xsi:nil attribute
*
* @param mixed $value
*
* @return bool
*/
public function isNull($value);
}
21 changes: 20 additions & 1 deletion src/XmlDeserializationVisitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
use JMS\Serializer\Metadata\ClassMetadata;
use JMS\Serializer\Metadata\PropertyMetadata;

class XmlDeserializationVisitor extends AbstractVisitor
class XmlDeserializationVisitor extends AbstractVisitor implements NullAwareVisitorInterface
{
private $objectStack;
private $metadataStack;
Expand Down Expand Up @@ -387,4 +387,23 @@ private function getDomDocumentTypeEntitySubset($data)

return $internalSubset;
}

/**
* @param mixed $value
*
* @return bool
*/
public function isNull($value)
{
if ($value instanceof \SimpleXMLElement) {
$xsiAttributes = $value->attributes('http://www.w3.org/2001/XMLSchema-instance');

//We have to keep the isset quiet, some tests give error: `Node no longer exists`; even though it evaluates to false
if (@isset($xsiAttributes['nil']) && (string) $xsiAttributes['nil'] === 'true') {
return true;
}
}

return $value === null;
}
}
14 changes: 14 additions & 0 deletions tests/Fixtures/ObjectWithNullProperty.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,21 @@

namespace JMS\Serializer\Tests\Fixtures;

use JMS\Serializer\Annotation\Type;

class ObjectWithNullProperty extends SimpleObject
{
/**
* @var null
* @Type("string")
*/
private $nullProperty = null;

/**
* @return null
*/
public function getNullProperty()
{
return $this->nullProperty;
}
}
19 changes: 19 additions & 0 deletions tests/Serializer/BaseSerializationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,25 @@ public function testSerializeNullObject()
);
}

public function testDeserializeNullObject()
{
if (!$this->hasDeserializer()) {
$this->markTestSkipped(sprintf('No deserializer available for format `%s`', $this->getFormat()));
}

$obj = new ObjectWithNullProperty('foo', 'bar');

/** @var ObjectWithNullProperty $dObj */
$dObj = $this->serializer->deserialize(
$this->getContent('simple_object_nullable'),
ObjectWithNullProperty::class,
$this->getFormat()
);

$this->assertEquals($obj, $dObj);
$this->assertNull($dObj->getNullProperty());
}

/**
* @dataProvider getTypes
*/
Expand Down
12 changes: 12 additions & 0 deletions tests/Serializer/XmlSerializationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
use JMS\Serializer\Handler\HandlerRegistry;
use JMS\Serializer\Metadata\StaticPropertyMetadata;
use JMS\Serializer\Naming\CamelCaseNamingStrategy;
use JMS\Serializer\Naming\PropertyNamingStrategyInterface;
use JMS\Serializer\Naming\SerializedNameAnnotationStrategy;
use JMS\Serializer\SerializationContext;
use JMS\Serializer\Serializer;
Expand All @@ -52,6 +53,7 @@
use JMS\Serializer\Tests\Fixtures\SimpleClassObject;
use JMS\Serializer\Tests\Fixtures\SimpleObject;
use JMS\Serializer\Tests\Fixtures\SimpleSubClassObject;
use JMS\Serializer\XmlDeserializationVisitor;
use JMS\Serializer\XmlSerializationVisitor;
use PhpCollection\Map;

Expand Down Expand Up @@ -488,6 +490,16 @@ public function testDeserializeEmptyString()
$this->deserialize('', 'stdClass');
}

public function testEvaluatesToNull()
{
$namingStrategy = $this->getMockBuilder(PropertyNamingStrategyInterface::class)->getMock();
$visitor = new XmlDeserializationVisitor($namingStrategy);
$element = simplexml_load_string('<empty xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>');

$this->assertTrue($visitor->isNull($element));
$this->assertTrue($visitor->isNull(null));
}

private function xpathFirstToString(\SimpleXMLElement $xml, $xpath)
{
$nodes = $xml->xpath($xpath);
Expand Down

0 comments on commit 3617f8d

Please sign in to comment.