Обмен данными между информационными базами — классическая задача для любого разработчика 1С. Одним из наиболее производительных, современных и удобных способов передачи объектов является их сериализация в формат JSON с использованием встроенного механизма XDTO. Однако при реализации этого механизма программисты нередко сталкиваются со скрытыми особенностями платформы «1С:Предприятие», которые приводят к трудночитаемым ошибкам, таким как «Тип не определен».
В этой статье мы подробно разберем, почему возникает данная ошибка при десериализации документов и других прикладных объектов, как контекст выполнения влияет на работу с типами данных, а также рассмотрим лучшие практики и скрытые нюансы использования СериализаторXDTO при обмене данными.
Для начала проанализируем ситуацию, с которой столкнулся автор темы. В базе-источнике выполняется сериализация объекта во встроенный JSON-формат:
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
СериализаторXDTO.ЗаписатьJSON(ЗаписьJSON, Выборка.Объект.ПолучитьОбъект(), НазначениеТипаXML.Неявное);
СериализованнаяСтрока = ЗаписьJSON.Закрыть();
В базе-приемнике полученная строка передается для обратного восстановления (десериализации):
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(СериализованнаяСтрока);
ДокОбъект = СериализаторXDTO.ПрочитатьJSON(ЧтениеJSON, Тип("ДокументОбъект.ПересортицаТоваров"));
ЧтениеJSON.Закрыть();
На первый взгляд код написан абсолютно верно. Но при его выполнении система выбрасывает исключение: «Тип не определен». В чем же дело?
Разгадка кроется в контексте выполнения кода. Автор темы честно признался, что пытался выполнить десериализацию на стороне клиента (например, непосредственно в модуле управляемой формы под директивой &НаКлиенте).
В платформе «1С:Предприятие» действует строгое разделение типов данных между клиентом и сервером:
ДокументОбъект.ИмяДокумента, СправочникОбъект.ИмяСправочника и т. д.) существуют только на сервере. На клиенте мы можем работать лишь с их ссылками (ДокументСсылка) или облегченными формами представления (ДанныеФормыСтруктура).ДокументОбъект недоступен на клиенте, вызов функции Тип("ДокументОбъект.ПересортицаТоваров") в клиентском контексте возвращает значение Неопределено.СериализаторXDTO.ПрочитатьJSON(), принимая вторым параметром значение Неопределено вместо валидного описания типа, не может сопоставить структуру JSON с объектом конфигурации и выдает ошибку «Тип не определен».Решение проблемы чрезвычайно простое: перенесите весь код, связанный с чтением, записью, сериализацией и десериализацией прикладных объектов 1С, в серверный контекст (в общий модуль с флагом «Сервер» или в процедуру с директивой &НаСервере или &НаСервереБезКонтекста).
Рассмотрим по шагам, как должен выглядеть правильный серверный метод десериализации объекта:
&НаСервереБезКонтекста
Функция ДесериализоватьДокументНаСервере(Знач СериализованнаяСтрока)
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(СериализованнаяСтрока);
// На сервере функция Тип() корректно вернет тип прикладного объекта
ТипПриемника = Тип("ДокументОбъект.ПересортицаТоваров");
Попытка
ДокОбъект = СериализаторXDTO.ПрочитатьJSON(ЧтениеJSON, ТипПриемника);
Исключение
ЗаписьЖурналаРегистрации("ОбменДанными", УровеньЖурналаРегистрации.Ошибка,,,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
ВызватьИсключение "Ошибка десериализации документа: " + КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
КонецПопытки;
ЧтениеJSON.Закрыть();
Возврат ДокОбъект; // Возвращаем ДокументОбъект для дальнейшей записи
КонецФункции
---
Перенос кода на сервер — это лишь первый шаг к построению надежной системы обмена. Давайте проанализируем сопутствующие механизмы сериализации JSON через XDTO, знание которых убережет вас от неочевидных багов при эксплуатации системы.
При вызове метода СериализаторXDTO.ЗаписатьJSON() третьим параметром передается системное перечисление НазначениеТипаXML. Оно имеет два значения:
ПрочитатьJSON(), иначе система не поймет, во что превратить входящий поток данных."#type": "jcfg:DocumentObject.ПересортицаТоваров"). При использовании этого режима указывать целевой тип при чтении необязательно — СериализаторXDTO автоматически распознает тип объекта и создаст нужный экземпляр в памяти.Давайте сравним структуру 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.Явное, поскольку это минимизирует ручную работу по сопоставлению типов при загрузке данных.
Малоизвестный, но крайне коварный нюанс сериализации XDTO в 1С — это жесткая привязка к порядку следования реквизитов в структуре конфигурации. Схема XDTO формируется динамически на основе порядка реквизитов, табличных частей и их колонок, заданного в дереве метаданных конфигуратора.
Если в базе-источнике и базе-приемнике конфигурации незначительно отличаются по структуре (например, в одной базе реквизит «Организация» расположен выше реквизита «Склад», а в другой — наоборот), то десериализация через XDTO может завершиться критической ошибкой несоответствия типов, даже если состав реквизитов на 100% совпадает.
В распределенных информационных базах (РИБ) эта проблема возникает редко, так как конфигурации идентичны по определению. Однако, если вы обновляете конфигурацию динамически или выполняете обмен до того, как база-приемник применила актуальный файл обновления конфигурации (1Cv8.gld), загрузка гарантированно упадет с ошибкой XDTO.
Когда вы сериализуете прикладной объект (например, документ), все его реквизиты ссылочного типа (номенклатура, контрагенты, договоры) записываются в JSON в виде их уникальных идентификаторов (GUID/UUID).
При десериализации документа в базе-приемнике платформа автоматически подставляет эти UUID в соответствующие поля. Но что произойдет, если в базе-приемнике на момент загрузки документа еще не создан справочник с таким UUID?
<Объект не найден> (8d3f11bc-...).Чтобы избежать этой проблемы, всегда обеспечивайте первоочередную (или совместную в одном пакете) выгрузку нормативно-справочной информации (НСИ) перед отправкой документов.
Если вам требуется вмешаться в процесс десериализации «на лету» (например, пересчитать суммы, подменить GUID склада или заполнить пустые реквизиты значениями по умолчанию), вы можете использовать специальный механизм — функцию восстановления.
Эта функция передается в метод ПрочитатьJSON() третьим параметром. Давайте посмотрим на пример реализации:
&НаСервере
Функция ОбработатьСвойстваПриИмпорте(Свойство, Значение, ДополнительныеПараметры) Экспорт
// Пример: подменяем склад при загрузке, если пришел определенный UUID
Если Свойство = "Склад" И Значение = "8d3f11bc-a2b6-11da-8ad6-505054503030" Тогда
// Возвращаем ссылку на предопределенный или дефолтный склад базы-приемника
Возврат Справочники.Склады.ОсновнойСклад;
КонецЕсли;
// Для всех остальных свойств оставляем стандартное значение
Возврат Значение;
КонецФункции
&НаСервере
Процедура ЗагрузитьСИспользованиемОбработчика(СериализованнаяСтрока)
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(СериализованнаяСтрока);
// Передаем описание оповещения на экспортную функцию обработки
ФункцияВосстановления = Новый ОписаниеОповещения("ОбработатьСвойстваПриИмпорте", ЭтотОбъект);
ДокОбъект = СериализаторXDTO.ПрочитатьJSON(ЧтениеJSON, Тип("ДокументОбъект.ПересортицаТоваров"), ФункцияВосстановления);
// Записываем полученный объект в базу данных
ДокОбъект.Записать(РежимЗаписиДокумента.Проведение);
ЧтениеJSON.Закрыть();
КонецПроцедуры
Использование функции восстановления позволяет гибко адаптировать входящие данные под специфику конкретной информационной базы без необходимости предварительного ручного парсинга JSON в структуры соответствий.
Применение механизма СериализаторXDTO для сериализации и десериализации данных в JSON — мощный и лаконичный инструмент платформы «1С:Предприятие 8.3». Чтобы защитить свой код от ошибок при его использовании, всегда придерживайтесь трех главных правил:
НазначениеТипаXML.Явное для автоматического определения типов платформой.