Как исправить ошибку «Тип не определен» при десериализации документа через JSON в 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Обмен данными между информационными базами — классическая задача для любого разработчика 1С. Одним из наиболее производительных, современных и удобных способов передачи объектов является их сериализация в формат JSON с использованием встроенного механизма XDTO. Однако при реализации этого механизма программисты нередко сталкиваются со скрытыми особенностями платформы «1С:Предприятие», которые приводят к трудночитаемым ошибкам, таким как «Тип не определен».

В этой статье мы подробно разберем, почему возникает данная ошибка при десериализации документов и других прикладных объектов, как контекст выполнения влияет на работу с типами данных, а также рассмотрим лучшие практики и скрытые нюансы использования СериализаторXDTO при обмене данными.

Выясняем причину: почему возникает ошибка «Тип не определен»?

Для начала проанализируем ситуацию, с которой столкнулся автор темы. В базе-источнике выполняется сериализация объекта во встроенный JSON-формат:


ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
СериализаторXDTO.ЗаписатьJSON(ЗаписьJSON, Выборка.Объект.ПолучитьОбъект(), НазначениеТипаXML.Неявное);
СериализованнаяСтрока = ЗаписьJSON.Закрыть();

В базе-приемнике полученная строка передается для обратного восстановления (десериализации):


ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(СериализованнаяСтрока);
ДокОбъект = СериализаторXDTO.ПрочитатьJSON(ЧтениеJSON, Тип("ДокументОбъект.ПересортицаТоваров"));    
ЧтениеJSON.Закрыть();

На первый взгляд код написан абсолютно верно. Но при его выполнении система выбрасывает исключение: «Тип не определен». В чем же дело?

Разгадка кроется в контексте выполнения кода. Автор темы честно признался, что пытался выполнить десериализацию на стороне клиента (например, непосредственно в модуле управляемой формы под директивой &НаКлиенте).

В платформе «1С:Предприятие» действует строгое разделение типов данных между клиентом и сервером:

  1. Объекты базы данных (такие как ДокументОбъект.ИмяДокумента, СправочникОбъект.ИмяСправочника и т. д.) существуют только на сервере. На клиенте мы можем работать лишь с их ссылками (ДокументСсылка) или облегченными формами представления (ДанныеФормыСтруктура).
  2. Поскольку сам тип ДокументОбъект недоступен на клиенте, вызов функции Тип("ДокументОбъект.ПересортицаТоваров") в клиентском контексте возвращает значение Неопределено.
  3. Метод СериализаторXDTO.ПрочитатьJSON(), принимая вторым параметром значение Неопределено вместо валидного описания типа, не может сопоставить структуру JSON с объектом конфигурации и выдает ошибку «Тип не определен».

Решение проблемы чрезвычайно простое: перенесите весь код, связанный с чтением, записью, сериализацией и десериализацией прикладных объектов 1С, в серверный контекст (в общий модуль с флагом «Сервер» или в процедуру с директивой &НаСервере или &НаСервереБезКонтекста).

Рассмотрим по шагам, как должен выглядеть правильный серверный метод десериализации объекта:


&НаСервереБезКонтекста
Функция ДесериализоватьДокументНаСервере(Знач СериализованнаяСтрока)
    
    ЧтениеJSON = Новый ЧтениеJSON;
    ЧтениеJSON.УстановитьСтроку(СериализованнаяСтрока);
    
    // На сервере функция Тип() корректно вернет тип прикладного объекта
    ТипПриемника = Тип("ДокументОбъект.ПересортицаТоваров");
    
    Попытка
        ДокОбъект = СериализаторXDTO.ПрочитатьJSON(ЧтениеJSON, ТипПриемника);
    Исключение
        ЗаписьЖурналаРегистрации("ОбменДанными", УровеньЖурналаРегистрации.Ошибка,,, 
            ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
        ВызватьИсключение "Ошибка десериализации документа: " + КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
    КонецПопытки;
    
    ЧтениеJSON.Закрыть();
    
    Возврат ДокОбъект; // Возвращаем ДокументОбъект для дальнейшей записи
    
КонецФункции

---

Глубокий анализ механизма СериализаторXDTO: важные нюансы обмена

Перенос кода на сервер — это лишь первый шаг к построению надежной системы обмена. Давайте проанализируем сопутствующие механизмы сериализации JSON через XDTO, знание которых убережет вас от неочевидных багов при эксплуатации системы.

1. Явное и неявное назначение типов (НазначениеТипаXML)

При вызове метода СериализаторXDTO.ЗаписатьJSON() третьим параметром передается системное перечисление НазначениеТипаXML. Оно имеет два значения:

Давайте сравним структуру JSON для обоих случаев на примере элементарного справочника.

При неявном назначении типов структура выглядит так:


{
  "Ref": "1178ebb1-a2b6-11da-8ad6-505054503030",
  "DeletionMark": false,
  "Code": "00001",
  "Description": "ООО Торговый Дом"
}

При явном назначении типов структура усложняется служебными свойствами 1С:


{
  "#type": "jcfg:CatalogObject.Контрагенты",
  "#value": {
    "Ref": "1178ebb1-a2b6-11da-8ad6-505054503030",
    "DeletionMark": false,
    "Code": "00001",
    "Description": "ООО Торговый Дом"
  }
}

Для внутренних обменов между базами 1С рекомендуется использовать НазначениеТипаXML.Явное, поскольку это минимизирует ручную работу по сопоставлению типов при загрузке данных.

2. Зависимость от порядка реквизитов в метаданных

Малоизвестный, но крайне коварный нюанс сериализации XDTO в 1С — это жесткая привязка к порядку следования реквизитов в структуре конфигурации. Схема XDTO формируется динамически на основе порядка реквизитов, табличных частей и их колонок, заданного в дереве метаданных конфигуратора.

Если в базе-источнике и базе-приемнике конфигурации незначительно отличаются по структуре (например, в одной базе реквизит «Организация» расположен выше реквизита «Склад», а в другой — наоборот), то десериализация через XDTO может завершиться критической ошибкой несоответствия типов, даже если состав реквизитов на 100% совпадает.

В распределенных информационных базах (РИБ) эта проблема возникает редко, так как конфигурации идентичны по определению. Однако, если вы обновляете конфигурацию динамически или выполняете обмен до того, как база-приемник применила актуальный файл обновления конфигурации (1Cv8.gld), загрузка гарантированно упадет с ошибкой XDTO.

3. Проблема «битых» ссылок

Когда вы сериализуете прикладной объект (например, документ), все его реквизиты ссылочного типа (номенклатура, контрагенты, договоры) записываются в JSON в виде их уникальных идентификаторов (GUID/UUID).

При десериализации документа в базе-приемнике платформа автоматически подставляет эти UUID в соответствующие поля. Но что произойдет, если в базе-приемнике на момент загрузки документа еще не создан справочник с таким UUID?

Чтобы избежать этой проблемы, всегда обеспечивайте первоочередную (или совместную в одном пакете) выгрузку нормативно-справочной информации (НСИ) перед отправкой документов.

4. Использование функции восстановления при десериализации

Если вам требуется вмешаться в процесс десериализации «на лету» (например, пересчитать суммы, подменить GUID склада или заполнить пустые реквизиты значениями по умолчанию), вы можете использовать специальный механизм — функцию восстановления.

Эта функция передается в метод ПрочитатьJSON() третьим параметром. Давайте посмотрим на пример реализации:


&НаСервере
Функция ОбработатьСвойстваПриИмпорте(Свойство, Значение, ДополнительныеПараметры) Экспорт
    
    // Пример: подменяем склад при загрузке, если пришел определенный UUID
    Если Свойство = "Склад" И Значение = "8d3f11bc-a2b6-11da-8ad6-505054503030" Тогда
        // Возвращаем ссылку на предопределенный или дефолтный склад базы-приемника
        Возврат Справочники.Склады.ОсновнойСклад;
    КонецЕсли;
    
    // Для всех остальных свойств оставляем стандартное значение
    Возврат Значение;
    
КонецФункции

&НаСервере
Процедура ЗагрузитьСИспользованиемОбработчика(СериализованнаяСтрока)
    
    ЧтениеJSON = Новый ЧтениеJSON;
    ЧтениеJSON.УстановитьСтроку(СериализованнаяСтрока);
    
    // Передаем описание оповещения на экспортную функцию обработки
    ФункцияВосстановления = Новый ОписаниеОповещения("ОбработатьСвойстваПриИмпорте", ЭтотОбъект);
    
    ДокОбъект = СериализаторXDTO.ПрочитатьJSON(ЧтениеJSON, Тип("ДокументОбъект.ПересортицаТоваров"), ФункцияВосстановления);
    
    // Записываем полученный объект в базу данных
    ДокОбъект.Записать(РежимЗаписиДокумента.Проведение);
    
    ЧтениеJSON.Закрыть();
    
КонецПроцедуры

Использование функции восстановления позволяет гибко адаптировать входящие данные под специфику конкретной информационной базы без необходимости предварительного ручного парсинга JSON в структуры соответствий.

Резюме

Применение механизма СериализаторXDTO для сериализации и десериализации данных в JSON — мощный и лаконичный инструмент платформы «1С:Предприятие 8.3». Чтобы защитить свой код от ошибок при его использовании, всегда придерживайтесь трех главных правил:

  1. Выполняйте чтение и запись прикладных объектов (документов, справочников) строго в серверном контексте.
  2. Внимательно следите за идентичностью структуры метаданных и версиями конфигураций в обменивающихся базах.
  3. Для простых внутренних обменов используйте НазначениеТипаXML.Явное для автоматического определения типов платформой.
← На главную