Symfony сериализатор не может десериализовать в \ DateTime - PullRequest
1 голос
/ 10 февраля 2020

Я пытаюсь десериализовать json с сериализатором Symfony в DTO, но я всегда получаю исключение Symfony/Component/Serializer/Exception/MissingConstructorArgumentsException with message 'Cannot create an instance of DateTime from serialized data because its constructor requires parameter "time" to be present.'.

Мой DTO выглядит так:

class ResponseDto
{
    /** @var \DateTime */
    private $creationDate;


    /** @var NestedObject */
    private $result;


    public function __construct(
        \DateTime $creationDate,
        NestedObject $result
    ) { /* … */ }

    public function getCreationDate(): \DateTime
    {
        return $this->creationDate;
    }

    public function getResult(): NestedObject
    {
        return $this->result;
    }
}

с json вот так:

[
  {
    "result":{
      "operations":{
        "successful":319698,
        "failed":2,
        "total":319700
      }
    },
    "creationDate":"2020-02-10T03:01:53.357Z"
  },
  // …
]

Вызов десериализации также прост:

$serializer->deserialize(
    $data,
    ResponseDto::class . '[]',
    'json'
);

И все необходимые нормализаторы (и пакет symfony / property-info) также установлены / зарегистрированы:

$ bin/console debug:container serializer --show-arguments

Information for Service "serializer"
====================================

 Serializer serializes and deserializes data.

 ---------------- ----------------------------------------- 
  Option           Value                                    
 ---------------- ----------------------------------------- 
  Service ID       serializer                               
  Class            Symfony\Component\Serializer\Serializer  
  Tags             -                                        
  Public           yes                                      
  Synthetic        no                                       
  Lazy             no                                       
  Shared           yes                                      
  Abstract         no                                       
  Autowired        no                                       
  Autoconfigured   no                                       
  Arguments        Array (9 element(s))                     
                   Array (5 element(s))                     
 ---------------- ----------------------------------------- 


$ bin/console debug:container --tag serializer.normalizer

Symfony Container Services Tagged with "serializer.normalizer" Tag
==================================================================

 ------------------------------------------------- ---------- --------------------------------------------------------------------------- 
  Service ID                                        priority   Class name                                                                 
 ------------------------------------------------- ---------- --------------------------------------------------------------------------- 
  fos_rest.serializer.form_error_normalizer         -10        FOS\RestBundle\Serializer\Normalizer\FormErrorNormalizer                   
  reporting.reader.serializer                                  Symfony\Component\Serializer\Serializer                                    
  serializer.denormalizer.array                     -990       Symfony\Component\Serializer\Normalizer\ArrayDenormalizer                  
  serializer.normalizer.constraint_violation_list   -915       Symfony\Component\Serializer\Normalizer\ConstraintViolationListNormalizer  
  serializer.normalizer.data_uri                    -920       Symfony\Component\Serializer\Normalizer\DataUriNormalizer                  
  serializer.normalizer.dateinterval                -915       Symfony\Component\Serializer\Normalizer\DateIntervalNormalizer             
  serializer.normalizer.datetime                    -910       Symfony\Component\Serializer\Normalizer\DateTimeNormalizer                 
  serializer.normalizer.json_serializable           -900       Symfony\Component\Serializer\Normalizer\JsonSerializableNormalizer         
  serializer.normalizer.object                      -1000      Symfony\Component\Serializer\Normalizer\ObjectNormalizer                   
 ------------------------------------------------- ---------- --------------------------------------------------------------------------- 

Почему сериализатор не может десериализовать данные в \DateTime объект ? DateTimeNormalizer::supportsDenormalization() также вызывается и возвращает true для свойства, но DateTimeNormalizer::denormalize() никогда не вызывается.

Интересный факт: если я изменю подсказку типа на \DateTimeInterface, сериализатор может десериализовать данные, но выдает \DateTimeImmutable (к сожалению, мне нужно \DateTime объектов).

1 Ответ

1 голос
/ 11 февраля 2020

Я обнаружил проблему:

Как показано выше, существует служба reporting.reader.serializer, помеченная как serializer.normalizer, но только с небольшим набором настроенных нормализаторов и кодеров:

services:
    reporting.reader.serializer:
        class: Symfony\Component\Serializer\Serializer
        arguments:
            - ['@serializer.normalizer.object']
            - ['@serializer.encoder.csv']

Этот сериализатор не имеет приоритета, поэтому он вызывается перед DateTimeNormalizer. Таким образом, все объекты создаются этим сериализатором, но этот сериализатор не может десериализовать интерфейсы, такие как \DateTimeInterface (вот почему этот тип подсказки сработал, и я получил \DateTimeImmutable).

Я исправил это, установив autoconfigure: false для услуги reporting.reader.serializer.

...