6

I'm trying to write a REST API which consumes a JSON from a PUT request in Symfony2. Deserializing the JSON to an entity sort of works – but the JMS Serializer seems to coerce types from the JSON instead of throwing an exception if the type of a property in the JSON does not match the entity’s corresponding property.

For example …</p>

{ "id" : "123" }

… will result in …</p>

int(123)

… if the property id is defined as an integer in the entity.

But I would like JMS Serializer to throw an exception instead. Does anyone know how to achieve this?

Update 2016-02-27

One problem with JMS Serializer’s type handling I found is this:

{ "id" : "n123" }

will result in …</p>

int(0)

which is totally undesired.

Can someone please point me into the right direction?

4

2 回答 2

6

Github 获得帮助后,我想就我自己的问题分享一个答案。

解决方案的关键是使用实现JMS\Serializer\Handler\SubscribingHandlerInterface(例如 a StrictIntegerHandler)的自定义处理程序。

<?php
namespace MyBundle\Serializer;

use JMS\Serializer\Context;
use JMS\Serializer\GraphNavigator;
use JMS\Serializer\Handler\SubscribingHandlerInterface;
use JMS\Serializer\JsonDeserializationVisitor;
use JMS\Serializer\JsonSerializationVisitor;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;

class StrictIntegerHandler implements SubscribingHandlerInterface
{
    public static function getSubscribingMethods()
    {
        return [
            [
                'direction' => GraphNavigator::DIRECTION_DESERIALIZATION,
                'format' => 'json',
                'type' => 'strict_integer',
                'method' => 'deserializeStrictIntegerFromJSON',
            ],
            [
                'direction' => GraphNavigator::DIRECTION_SERIALIZATION,
                'format' => 'json',
                'type' => 'strict_integer',
                'method' => 'serializeStrictIntegerToJSON',
            ],
        ];
    }

    public function deserializeStrictIntegerFromJSON(JsonDeserializationVisitor $visitor, $data, array $type)
    {
        return $data;
    }

    public function serializeStrictIntegerToJSON(JsonSerializationVisitor $visitor, $data, array $type, Context $context)
    {
        return $visitor->visitInteger($data, $type, $context);
    }
}

然后,您需要将序列化程序定义为服务:

services:
    mybundle.serializer.strictinteger:
        class: MyBundle\Serializer\StrictIntegerHandler
        tags:
            - { name: jms_serializer.subscribing_handler }

然后您将能够使用类型strict_integer

MyBundle\Entity\MyEntity:
    exclusion_policy: ALL
    properties:
        id:
            expose: true
            type: strict_integer

然后在控制器中反序列化照常工作。

奖励:现在使用类型验证器终于有意义了:

MyBundle\Entity\MyEntity:
    properties:
        id:
            - Type:
                type: integer
                message: id {{ value }} is not an integer.

我希望这可以帮助那些有同样问题的人。

于 2016-04-20T12:58:05.577 回答
3

基于 reieRMeister 的回答,当谈到 JSON 反序列化时,我认为默认强制原始类型是不明智的。

strict_integer当需要通过为每个属性显式设置类型来区分“严格”和“松散”类型时,reieRMaster 的答案很好。但是,如果您希望使用使用原则元数据确定类型的内置功能,这会变得有些乏味。

jms_serializer.json_deserialization_visitor.class您可以通过使用您自己的类之一来覆盖所有原始类型的默认行为,如下所示:

<?php
namespace MyBundle\Serializer\Visitor;

use JMS\Serializer\JsonDeserializationVisitor;
use JMS\Serializer\Context;

class JsonNativeDeserializationVisitor extends JsonDeserializationVisitor
{

    public function visitString($data, array $type, Context $context)
    {
        return $data;
    }

    public function visitBoolean($data, array $type, Context $context)
    {
        return $data;
    }

    public function visitInteger($data, array $type, Context $context)
    {
        return $data;
    }

    public function visitDouble($data, array $type, Context $context)
    {
        return $data;
    }

}

并在 services.xml(或 services.yml)中覆盖jms_serializer.json_deserialization_visitor.class

<parameters>
    <parameter key="jms_serializer.json_deserialization_visitor.class">MyBundle\Serializer\Visitor\JsonNativeDeserializationVisitor</parameter>
</parameters>

明白了! 确保您的包在 JMSSerializer 包之后注册否则上述方法将不起作用。如何做到这一点在此处描述

于 2016-06-30T11:28:43.173 回答