如何让JMS Serializer在反序列化JSON而不是强制类型时引发异常?

时间:2016-02-19 10:03:21

标签: symfony json-deserialization jmsserializerbundle jms-serializer

我正在尝试编写一个REST API,它在Symfony2中使用来自PUT请求的JSON。将JSON反序列化为实体类型 - 但是如果JSON中的属性类型与实体的相应属性不匹配,JMS Serializer似乎强制来自JSON的类型而不是抛出异常。

例如......

{ "id" : "123" }

...将导致......

int(123)

...如果属性id被定义为实体中的整数。

但我希望JMS Serializer能够抛出异常。有谁知道如何实现这个目标?

更新2016-02-27

我发现JMS Serializer的类型处理的一个问题是:

{ "id" : "n123" }

将导致......

int(0)

完全不受欢迎。

有人可以指出我正确的方向吗?

2 个答案:

答案 0 :(得分:6)

getting help over at Github之后我想就自己的问题分享答案。

解决方案的关键是使用实现JMS\Serializer\Handler\SubscribingHandlerInterface的自定义处理程序(例如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.

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

答案 1 :(得分: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>

<强>疑难杂症! 确保您的软件包已注册 AFTER JMSSerializer软件包,否则上述操作无效。 How to do that is described here