При работе с обменами данными в формате JSON разработчики 1С часто сталкиваются с неочевидным, на первый взгляд, поведением системы. Попытка записать в JSON структуру, содержащую значение типа Null, приводит к ошибке, в то время как значение Неопределено обрабатывается корректно и преобразуется в null. Это расходится с интуитивным ожиданием, ведь именно null является стандартным типом для JSON, а undefined (аналог Неопределено) в стандарте отсутствует.
Давайте разберемся, почему платформа "1С:Предприятие" реализована именно так, в чем разница между этими типами и как правильно готовить данные для сериализации.
Для начала проанализируем теоретическую базу. Стандарт JSON (описанный в RFC 8259) строго определяет список допустимых типов значений:
true или false)null для обозначения отсутствия значенияКак мы видим, в этом стандарте нет типа "undefined". В то же время в платформе 1С существуют два разных типа для обозначения "пустых" или отсутствующих значений:
<strong>Неопределено</strong> — это универсальный маркер отсутствия значения. Он используется как значение по умолчанию для неинициализированных переменных, а также для реквизитов объектов с составным типом данных. По сути, это означает "значение еще не было задано".<strong>Null</strong> — это специфический тип, который используется почти исключительно при работе с базой данных. Он представляет собой значение NULL из SQL и обычно встречается в результатах запросов (например, при левом соединении, когда в присоединяемой таблице не нашлось соответствующей записи).Именно эта разница в семантике и является ключом к пониманию логики сериализации в 1С.
Разработчики платформы "1С:Предприятие" сопоставили внутренние типы данных с типами стандарта JSON следующим образом:
1. Неопределено из 1С преобразуется в null в JSON.
Это логичное и правильное решение. Поскольку Неопределено в 1С — это основной способ указать на отсутствие значения в бизнес-логике, его сопоставили с единственным аналогичным по смыслу типом в JSON — null. Это поведение официально задокументировано. Например, в руководстве разработчика прямо указано: "Неопределено – сериализуется в null".
2. Null из 1С не поддерживается для прямой записи в JSON.
Попытка сериализовать структуру или массив, где хотя бы одно из значений имеет тип Null, вызовет ошибку "Передано значение недопустимого типа". Почему так сделано? Тип Null в 1С не является общеупотребительным "пустым" значением. Это узкоспециализированный тип для результатов взаимодействия с СУБД. Исключив его из автоматической сериализации, разработчики платформы предотвращают потенциальную неоднозначность и ошибки при обмене данными с внешними системами, которые не ожидают такой специфики.
В Синтакс-Помощнике, в описании метода ЗаписатьJSON(), можно найти полный список поддерживаемых типов. Важно обратить внимание на примечание, в котором явно указан тип Неопределено, но отсутствует Null.
Рассмотрим на простом примере, как это работает на практике. Допустим, у нас есть две структуры, одна с Неопределено, другая с Null.
Корректный код, который отработает без ошибок:
СтруктураДляJSON = Новый Структура;
СтруктураДляJSON.Вставить("РабочееЗначение", "Какой-то текст");
СтруктураДляJSON.Вставить("НеопределенноеЗначение", Неопределено);
// Этот код выполнится успешно
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, СтруктураДляJSON);
Результат = ЗаписьJSON.Закрыть();
// В переменной 'Результат' будет строка:
// {"РабочееЗначение":"Какой-то текст","НеопределенноеЗначение":null}
Сообщить(Результат);
Код, который вызовет ошибку:
СтруктураСОшибкой = Новый Структура;
СтруктураСОшибкой.Вставить("РабочееЗначение", "Какой-то текст");
СтруктураСОшибкой.Вставить("NullЗначение", Null); // Проблемное значение
// Этот код вызовет исключение
Попытка
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, СтруктураСОшибкой);
Результат = ЗаписьJSON.Закрыть();
Исключение
// Будет выведено сообщение:
// "Ошибка при вызове метода контекста (ЗаписатьJSON): Передано значение недопустимого типа"
Сообщить(ОписаниеОшибки());
КонецПопытки;
Главное правило — перед сериализацией необходимо подготовить данные. Если ваши данные получены из запроса к базе данных, они могут содержать значения типа Null. Их нужно явно заменить на Неопределено.
Посмотрим на пример обработки результата запроса:
// Допустим, у нас есть результат запроса
РезультатЗапроса = Запрос.Выполнить().Выгрузить();
МассивДляJSON = Новый Массив;
// Обходим строки результата и формируем массив структур для сериализации
Для Каждого СтрокаТЗ Из РезультатЗапроса Цикл
СтруктураСтроки = Новый Структура;
Для Каждого Колонка Из РезультатЗапроса.Колонки Цикл
ЗначениеПоля = СтрокаТЗ[Колонка.Имя];
// Ключевой момент: заменяем Null на Неопределено
Если ТипЗнч(ЗначениеПоля) = Тип("Null") Тогда
СтруктураСтроки.Вставить(Колонка.Имя, Неопределено);
Иначе
СтруктураСтроки.Вставить(Колонка.Имя, ЗначениеПоля);
КонецЕсли;
КонецЦикла;
МассивДляJSON.Добавить(СтруктураСтроки);
КонецЦикла;
// Теперь этот массив можно безопасно записывать в JSON
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, МассивДляJSON);
РезультатJSON = ЗаписьJSON.Закрыть();
Такой подход гарантирует, что все отсутствующие значения в вашей структуре данных будут корректно преобразованы в стандартное для JSON значение null.
В итоге, можно сделать следующие выводы:
Неопределено (общее отсутствие значения) и Null (отсутствие значения из БД).Неопределено, чтобы получить на выходе null.Null на Неопределено перед их передачей в метод ЗаписатьJSON.