如何使 JMS 序列化程序在反序列化 JSON 而不是强制类型时抛出异常?

How to make JMS Serializer throw an exception on deserializing JSON instead of coercing types?

我正在尝试编写一个 REST API,它使用来自 Symfony2 中 PUT 请求的 JSON。将 JSON 反序列化为实体类型的作品——但 JMS 序列化器似乎从 JSON 强制类型,而不是在 [=37= 中的 属性 类型时抛出异常]不匹配实体对应的属性.

例如……

{ "id" : "123" }

… 将导致…

int(123)

…如果属性 id在实体中定义为整数。

但我希望 JMS 序列化程序改为抛出异常。有谁知道如何做到这一点?

更新2016-02-27

我发现 JMS 序列化程序类型处理的一个问题是:

{ "id" : "n123" }

将导致……

int(0)

这是完全不受欢迎的。

有人能给我指出正确的方向吗?

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.

希望对遇到同样问题的人有所帮助。

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

当需要通过将每个 属性 的类型显式设置为 strict_integer 来区分 "strict" 和 "loose" 类型时,

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