You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Symfony中DateTime类型反序列化失败,如何解决?

问题分析

你的问题根源在于三个核心点:

  1. Normalizer功能局限性:使用的GetSetMethodNormalizer是基础属性访问器,只会直接调用setter方法,不会根据属性类型自动委托DateTimeNormalizer完成字符串到DateTimeInterface的转换。
  2. 属性命名不匹配:JSON字段是蛇形命名date_of_birth,但类属性是驼峰命名dateOfBirth,两者无法自动映射。
  3. 注解未被解析:#[Context]注解需要Serializer通过注解读取器识别,否则配置的日期格式规则不会生效。
解决方案

1. 替换为ObjectNormalizer(推荐)

ObjectNormalizer支持类型解析、注解读取和自动委托对应类型的Normalizer,能解决类型转换问题。修改Serializer初始化代码:

use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
use Doctrine\Common\Annotations\AnnotationReader;

// 初始化注解读取器,识别#[Context]等注解
$classMetadataFactory = new ClassMetadataFactory(
    new AnnotationLoader(new AnnotationReader())
);

$serializer = new Serializer(
    [
        new ArrayDenormalizer(),
        new DateTimeNormalizer(),
        new ObjectNormalizer($classMetadataFactory),
    ],
    [new JsonEncoder()]
);

2. 处理属性命名映射

针对JSON蛇形、类属性驼峰的命名差异,给ObjectNormalizer添加命名转换器:

use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;

// ... 其他代码

$normalizer = new ObjectNormalizer(
    $classMetadataFactory,
    new CamelCaseToSnakeCaseNameConverter()
);

$serializer = new Serializer(
    [
        new ArrayDenormalizer(),
        new DateTimeNormalizer(),
        $normalizer,
    ],
    [new JsonEncoder()]
);

3. 单类测试示例修改(完整可运行)

<?php

namespace App\Controller;

use DateTimeInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\Annotation\Context;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
use Doctrine\Common\Annotations\AnnotationReader;
use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;

class TestController extends AbstractController
{
    #[Route(path: '/test', name: 'app_test')]
    public function index(): Response
    {
        $json = '{"date_of_birth":"2023-01-31"}';

        $classMetadataFactory = new ClassMetadataFactory(
            new AnnotationLoader(new AnnotationReader())
        );

        $serializer = new Serializer(
            [
                new ArrayDenormalizer(),
                new DateTimeNormalizer(),
                new ObjectNormalizer(
                    $classMetadataFactory,
                    new CamelCaseToSnakeCaseNameConverter()
                ),
            ],
            [new JsonEncoder()]
        );

        $testPersonFromJson = $serializer->deserialize($json, TestPerson::class, 'json');

        return $this->json($testPersonFromJson);
    }
}

class TestPerson {
    #[Context([DateTimeNormalizer::FORMAT_KEY => 'Y-m-d'])]
    private ?DateTimeInterface $dateOfBirth = null;

    public function getDateOfBirth(): ?DateTimeInterface {
        return $this->dateOfBirth;
    }
    public function setDateOfBirth(?DateTimeInterface $dateOfBirth): self {
        $this->dateOfBirth = $dateOfBirth;

        return $this;
    }
}

4. 关键注意事项

  • Normalizer顺序:ArrayDenormalizer必须放在最前面(处理数组类型反序列化),DateTimeNormalizer要在ObjectNormalizer之前,确保对象属性处理时能找到对应的类型转换工具。
  • 依赖安装:若缺少doctrine/annotations包,执行composer require doctrine/annotations以支持注解读取。
  • 日期格式匹配:确保JSON日期字符串与#[Context]配置的Y-m-d格式完全一致,否则会抛出转换异常。

内容的提问来源于stack exchange,提问作者Krann Sock

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 23:40:34