Как исправить ошибку «Передано значение недопустимого типа» при записи JSON в 1С:Предприятии?

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

При разработке механизмов интеграции и обмена данными в среде 1С:Предприятие программисты регулярно сталкиваются с необходимостью сериализации объектов встроенного языка в формат JSON. Этот формат де-факто стал стандартом для веб-сервисов и API-интеграций. Однако при использовании стандартного метода ЗаписатьJSON разработчики часто сталкиваются с крайне неприятной ошибкой: «Передано значение недопустимого типа».

В этой статье мы подробно разберем причины возникновения этой ошибки, выясним принципиальную разницу между системными типами данных в контексте сериализации, а также рассмотрим эффективные практические способы ее решения. Кроме того, мы разберем сопутствующие проблемы с кодировкой (появление непонятных символов или «кракозябр») и научимся записывать JSON напрямую в память без создания временных файлов на диске.

Причина ошибки: почему ЗаписатьJSON отказывается работать

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

Если в сериализуемый массив или структуру попадает объект любого другого типа — например, ссылка на справочник (СправочникСсылка), уникальный идентификатор, двоичные данные или системный тип NULL — платформа немедленно прерывает выполнение кода и генерирует исключение «Передано значение недопустимого типа».

Различие между NULL и Неопределено

Проанализируем ключевое различие между типами NULL и Неопределено в 1С, так как именно здесь кроется корень большинства ошибок:

Попытка передать структуру, содержащую значение NULL, в метод ЗаписатьJSON гарантированно приведет к аварийному завершению работы программы.

Решение 1: Исправление логики запроса и обхода результатов

Очень часто недопустимые значения попадают в выборку из-за невнимательности при проектировании запросов и последующего обхода результатов. Рассмотрим типичную ситуацию: в запросе используется левое соединение с таблицей цен или упаковок. Если для какой-то номенклатурной позиции данные отсутствуют, в соответствующем поле вернется NULL.

Чтобы избежать этой проблемы на уровне СУБД, всегда используйте функцию ЕСТЬNULL в тексте запроса. Это позволит сразу заменить отсутствующие значения на пустые строки, нули или другие дефолтные примитивные типы:


ВЫБРАТЬ
    Номенклатура.Ссылка КАК Номенклатура,
    ЕСТЬNULL(Цены.Цена, 0) КАК Цена,
    ЕСТЬNULL(Упаковки.Наименование, "") КАК Упаковка
ИЗ
    Справочник.Номенклатура КАК Номенклатура
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Цены КАК Цены
        ПО Номенклатура.Ссылка = Цены.Номенклатура

Также важно обратить внимание на обход результатов запроса. Если мы используем обход по группировкам (ОбходРезультатаЗапроса.ПоГруппировкам) для построения иерархических структур данных, помните: в итоговых строках верхнего уровня детальные поля подчиненных таблиц будут иметь значение NULL. Пытаясь записать всю выборку целиком без предварительной проверки, мы обязательно столкнемся с ошибкой сериализации. Обходите только те уровни выборки, которые гарантированно содержат заполненные данные.

Решение 2: Использование функции преобразования (Callback)

Если структура данных слишком сложная или формируется динамически, ручная проверка каждого свойства на NULL или тип ссылки становится нерациональной. Для решения этой задачи разработчики платформы предусмотрели элегантный инструмент — Функцию преобразования.

Функция преобразования передается в качестве параметра в метод ЗаписатьJSON. Каждый раз, когда сериализатор встречает неподдерживаемый тип данных, он временно приостанавливает работу и передает управление в эту функцию. Наша задача — обработать неподдерживаемый тип и вернуть вместо него примитивное значение (например, строку или Неопределено).

Разберем по шагам, как реализовать этот механизм. Для начала создадим универсальную экспортную функцию в общем модуле (например, с именем РаботаСJSONГлобальный):


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

Теперь рассмотрим пример вызова сериализации с использованием нашей функции преобразования:


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

Этот подход гарантирует стабильную работу сериализатора при любых изменениях в структуре исходных данных. Даже если в структуре внезапно появится ссылка на новый справочник или поле со значением NULL, код выполнится без ошибок. Для быстрой проверки структур и генерации кода работы с данными подойдёт инструмент для валидации и генерации кода JSON в 1С.

Решение 3: Сериализация в память без использования файлов

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

Платформа 1С позволяет осуществлять все операции записи и чтения JSON непосредственно в оперативной памяти компьютера. Для этого у объекта ЗаписьJSON существует метод УстановитьСтроку(). Рассмотрим пример эффективной функции, которая принимает на вход структуру 1С и возвращает готовую строку JSON:


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

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

Решение 4: Устранение проблем с кодировкой (UTF-8 против ANSI)

Еще одна распространенная проблема при работе с JSON в 1С — появление некорректных символов (так называемых «кракозябр») при сохранении или чтении данных из файлов. Разберем по шагам физику этого процесса.

По умолчанию объект ЗаписьJSON всегда производит запись текстовой информации исключительно в кодировке UTF-8 (это жесткое требование спецификации формата JSON). В то же время, если разработчик пытается прочитать созданный файл с помощью объекта ЧтениеТекста или внешних утилит без явного указания кодировки, система пытается применить кодировку по умолчанию (для русскоязычных Windows-систем это ANSI / Windows-1251).

Из-за разницы кодировок (записано в UTF-8, прочитано в Windows-1251) весь русский текст превращается в нечитаемый набор символов. Чтобы этого избежать, всегда явно указывайте кодировку UTF-8 при чтении файлов конфигурации или обмена:


// Пример правильного чтения файла JSON с диска
ПутьКФайлу = "C:\temp\data.json";

ЧтениеТекста = Новый ЧтениеТекста;
// Явно указываем кодировку UTF-8 третьим параметром
ЧтениеТекста.Открыть(ПутьКФайлу, КодировкаТекста.UTF8);

ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.ОткрытьПоток(ЧтениеТекста);

Данные = ПрочитатьJSON(ЧтениеJSON);

ЧтениеJSON.Закрыть();
ЧтениеТекста.Закрыть();

Использование явного указания КодировкаТекста.UTF8 полностью решает любые проблемы с некорректным отображением кириллических символов при кроссплатформенном обмене данными.

Рекомендации по оптимизации работы с JSON в 1С

Для того чтобы ваши механизмы интеграции работали стабильно и быстро, придерживайтесь следующих правил:

  1. Минимизируйте использование диска. Используйте методы УстановитьСтроку() для записи и УстановитьСтроку() для чтения данных в памяти, если объемы выгрузок не превышают нескольких десятков мегабайт.
  2. Контролируйте типы данных. Всегда проверяйте результаты запросов на наличие NULL с помощью функций ЕСТЬNULL или обрабатывайте их на этапе обхода выборки.
  3. Внедряйте функции преобразования. Создайте один раз универсальный модуль преобразования недопустимых типов данных для JSON и используйте его во всех интеграционных механизмах вашей конфигурации.
  4. Соблюдайте стандарты кодирования. Помните, что JSON — это мир UTF-8. При работе с файлами всегда принудительно задавайте кодировку при открытии потоков чтения и записи.

Соблюдение этих простых рекомендаций убережет вас от неожиданных ошибок в фоновых заданиях и обеспечит высокую скорость работы ваших интеграционных решений. При необходимости создания готовых веб-сервисов без ручной сериализации структур можно использовать конструктор API для интеграции 1С в формате JSON.

← На главную