8000 [Serializer] int is valid when float is expected when deserializing JSON · symfony/symfony@023c604 · GitHub
[go: up one dir, main page]

Skip to content

Commit 023c604

Browse files
committed
[Serializer] int is valid when float is expected when deserializing JSON
1 parent c3a50b0 commit 023c604

File tree

2 files changed

+34
-5
lines changed

2 files changed

+34
-5
lines changed

src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\Serializer\Normalizer;
1313

1414
use Symfony\Component\PropertyAccess\Exception\InvalidArgumentException;
15+
use Symfony\Component\Serializer\Encoder\JsonEncoder;
1516
use Symfony\Component\Serializer\Exception\CircularReferenceException;
1617
use Symfony\Component\Serializer\Exception\LogicException;
1718
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
@@ -260,6 +261,16 @@ private function validateAndDenormalize($currentClass, $attribute, $data, $forma
260261
}
261262
}
262263

264+
// JSON only has a Number type corresponding to both int and float PHP types.
265+
// PHP's json_encode, JavaScript's JSON.stringify, Go's json.Marshal as well as most other JSON encoders convert
266+
// floating-point numbers like 12.0 to 12 (the decimal part is dropped when possible).
267+
// PHP's json_decode automatically converts Numbers without a decimal part to integers.
268+
// To circumvent this behavior, integers are converted to floats when denormalizing JSON based formats and when
269+
// a float is expected.
270+
if (false !== strpos($format, JsonEncoder::FORMAT) && Type::BUILTIN_TYPE_FLOAT === $builtinType && is_int($data)) {
271+
return (float) $data;
272+
}
273+
263274
if (call_user_func('is_'.$builtinType, $data)) {
264275
return $data;
265276
}

src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -537,11 +537,21 @@ public function testDenomalizeRecursive()
537537
'inners' => array(array('foo' => 1), array('foo' => 2)),
538538
), ObjectOuter::class);
539539

540-
$this->assertEquals('foo', $obj->getInner()->foo);
541-
$this->assertEquals('bar', $obj->getInner()->bar);
542-
$this->assertEquals('1988-01-21', $obj->getDate()->format('Y-m-d'));
543-
$this->assertEquals(1, $obj->getInners()[0]->foo);
544-
$this->assertEquals(2, $obj->getInners()[1]->foo);
540+
$this->assertSame('foo', $obj->getInner()->foo);
541+
$this->assertSame('bar', $obj->getInner()->bar);
542+
$this->assertSame('1988-01-21', $obj->getDate()->format('Y-m-d'));
543+
$this->assertSame(1, $obj->getInners()[0]->foo);
544+
$this->assertSame(2, $obj->getInners()[1]->foo);
545+
}
546+
547+
public function testAcceptJsonNumber()
548+
{
549+
$extractor = new PropertyInfoExtractor(array(), array(new PhpDocExtractor(), new ReflectionExtractor()));
550+
$normalizer = new ObjectNormalizer(null, null, null, $extractor);
551+
$serializer = new Serializer(array(new ArrayDenormalizer(), new DateTimeNormalizer(), $normalizer));
552+
553+
$this->assertSame(10.0, $serializer->denormalize(array('number' => 10), JsonNumber::class, 'json')->number);
554+
$this->assertSame(10.0, $serializer->denormalize(array('number' => 10), JsonNumber::class, 'jsonld')->number);
545555
}
546556

547557
/**
@@ -820,3 +830,11 @@ protected function isAllowedAttribute($classOrObject, $attribute, $format = null
820830
return false;
821831
}
822832
}
833+
834+
class JsonNumber
835+
{
836+
/**
837+
* @var float
838+
*/
839+
public $number;
840+
}

0 commit comments

Comments
 (0)
0