From d9fd3d0417f8080abf131f9ed6de3b3d993bd51a Mon Sep 17 00:00:00 2001 From: Egor Ivanov Date: Sat, 11 Apr 2026 00:32:07 +0300 Subject: [PATCH 01/13] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20=D0=9E=D0=BF=D0=B8=D1=81=D0=B0=D1=82=D0=B5=D0=BB?= =?UTF-8?q?=D1=8C=D0=94=D0=A2=D0=9E,=20=D0=B0=D0=BD=D0=BD=D0=BE=D1=82?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D0=B8=20=D0=A1=D0=B8=D0=BD=D0=BE=D0=BD=D0=B8?= =?UTF-8?q?=D0=BC=20=D0=B8=20=D0=97=D0=BD=D0=B0=D1=87=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5=D0=9F=D0=BE=D0=A3=D0=BC=D0=BE=D0=BB=D1=87=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D1=8E,=20=D1=82=D0=B5=D1=81=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packagedef | 3 + ...20\273\321\217\320\224\320\242\320\236.os" | 63 +++++++ ...20\273\321\214\320\224\320\242\320\236.os" | 70 ++++++++ ...21\207\320\260\320\275\320\270\321\216.os" | 24 +++ ...20\275\320\276\320\275\320\270\320\274.os" | 24 +++ ...20\265\321\202\321\200\320\276\320\262.os" | 71 ++++++++ ...21\213\320\271\320\224\320\242\320\236.os" | 10 ++ ...20\237\320\276\320\273\320\265\320\274.os" | 9 + ...20\275\320\270\320\274\320\276\320\274.os" | 8 + ...3\321\214\320\224\320\242\320\236_test.os" | 164 ++++++++++++++++++ 10 files changed, 446 insertions(+) create mode 100644 "src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265\320\237\320\276\320\273\321\217\320\224\320\242\320\236.os" create mode 100644 "src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236.os" create mode 100644 "src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\227\320\275\320\260\321\207\320\265\320\275\320\270\320\265\320\237\320\276\320\243\320\274\320\276\320\273\321\207\320\260\320\275\320\270\321\216.os" create mode 100644 "src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\241\320\270\320\275\320\276\320\275\320\270\320\274.os" create mode 100644 "tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236.os" create mode 100644 "tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\241\320\236\320\261\321\217\320\267\320\260\321\202\320\265\320\273\321\214\320\275\321\213\320\274\320\237\320\276\320\273\320\265\320\274.os" create mode 100644 "tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\241\320\241\320\270\320\275\320\276\320\275\320\270\320\274\320\276\320\274.os" create mode 100644 "tests/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236_test.os" diff --git a/packagedef b/packagedef index ac53ca7..b8cd2cf 100644 --- a/packagedef +++ b/packagedef @@ -19,6 +19,7 @@ .ЗависитОт("tempfiles") .ЗависитОт("1connector", "2.3.3") .ЗависитОт("reflector", "0.3.1") + .ЗависитОт("annotations") .РазработкаЗависитОт("coverage", "0.6.1") .РазработкаЗависитОт("1testrunner", "1.9.2") .РазработкаЗависитОт("1bdd", "1.14.0") @@ -26,4 +27,6 @@ .РазработкаЗависитОт("winow", "0.11.0") .ОпределяетКласс("МенеджерПараметров", "src/Классы/МенеджерПараметров.os") .ОпределяетКласс("КонструкторПараметров", "src/Классы/КонструкторПараметров.os") + .ОпределяетКласс("АннотацияЗначениеПоУмолчанию", "src/Классы/АннотацияЗначениеПоУмолчанию.os") + .ОпределяетКласс("АннотацияСиноним", "src/Классы/АннотацияСиноним.os") ; diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265\320\237\320\276\320\273\321\217\320\224\320\242\320\236.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265\320\237\320\276\320\273\321\217\320\224\320\242\320\236.os" new file mode 100644 index 0000000..5ab56c9 --- /dev/null +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265\320\237\320\276\320\273\321\217\320\224\320\242\320\236.os" @@ -0,0 +1,63 @@ +// Описание одного поля DTO-класса, полученное из аннотаций свойства + +Перем Имя Экспорт; // Строка - имя свойства класса +Перем Тип Экспорт; // Тип - тип значения (определяется из ЗначениеПоУмолчанию) +Перем ЗначениеПоУмолчанию Экспорт; // Произвольный - значение по умолчанию +Перем Синоним Экспорт; // Строка - альтернативное имя ключа в конфигурации +Перем Обязательное Экспорт; // Булево - признак обязательности (нет ЗначениеПоУмолчанию) + +// Конструктор описания поля +// +// Параметры: +// ИмяПоля - Строка - имя свойства класса +// +Процедура ПриСозданииОбъекта(Знач ИмяПоля) + + Имя = ИмяПоля; + Тип = Неопределено; + ЗначениеПоУмолчанию = Неопределено; + Синоним = Неопределено; + Обязательное = Истина; + +КонецПроцедуры + +// Устанавливает значение по умолчанию и определяет тип из него +// +// Параметры: +// Значение - Произвольный - значение по умолчанию +// +Процедура УстановитьЗначениеПоУмолчанию(Знач Значение) Экспорт + + ЗначениеПоУмолчанию = Значение; + Обязательное = Ложь; + + Если Не Значение = Неопределено Тогда + Тип = ТипЗнч(Значение); + КонецЕсли; + +КонецПроцедуры + +// Устанавливает синоним поля +// +// Параметры: +// НовыйСиноним - Строка - альтернативное имя ключа в конфигурации +// +Процедура УстановитьСиноним(Знач НовыйСиноним) Экспорт + Синоним = НовыйСиноним; +КонецПроцедуры + +// Возвращает ключ для поиска в конфигурации +// Если задан синоним — возвращает его, иначе — имя свойства +// +// Возвращаемое значение: +// Строка - ключ для поиска в конфигурации +// +Функция КлючКонфигурации() Экспорт + + Если Не Синоним = Неопределено Тогда + Возврат Синоним; + КонецЕсли; + + Возврат Имя; + +КонецФункции diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236.os" new file mode 100644 index 0000000..52fa3e3 --- /dev/null +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236.os" @@ -0,0 +1,70 @@ +#Использовать annotations +#Использовать reflector + +Перем КонтейнерАннотаций; +Перем Лог; + +// Описывает класс DTO: читает аннотации экспортных свойств и возвращает массив описаний полей +// +// Параметры: +// КлассОбъект - Объект - экземпляр DTO-класса с аннотированными свойствами +// +// Возвращаемое значение: +// Массив из ОписаниеПоляДТО - массив описаний полей DTO +// +Функция ОписатьКласс(Знач КлассОбъект) Экспорт + + РефлекторОбъекта = Новый РефлекторОбъекта(КлассОбъект); + Свойства = РефлекторОбъекта.ПолучитьТаблицуСвойств(Неопределено, Истина); + + ОписанияПолей = Новый Массив; + + Для Каждого Свойство Из Свойства Цикл + + Если Не Свойство.Экспорт Тогда + Продолжить; + КонецЕсли; + + ОписаниеПоля = Новый ОписаниеПоляДТО(Свойство.Имя); + + Для Каждого Аннотация Из Свойство.Аннотации Цикл + + ИмяАннотации = Врег(Аннотация.Имя); + + ОпределениеАннотации = КонтейнерАннотаций.ПолучитьОпределениеАннотации(Аннотация.Имя); + + Если ОпределениеАннотации = Неопределено Тогда + Продолжить; + КонецЕсли; + + ОбъектАннотации = ОпределениеАннотации.СоздатьОбъектАннотации(Аннотация); + + Если ИмяАннотации = "ЗНАЧЕНИЕПОУМОЛЧАНИЮ" Тогда + + ОписаниеПоля.УстановитьЗначениеПоУмолчанию(ОбъектАннотации.Значение()); + + ИначеЕсли ИмяАннотации = "СИНОНИМ" Тогда + + ОписаниеПоля.УстановитьСиноним(ОбъектАннотации.Синоним()); + + КонецЕсли; + + КонецЦикла; + + ОписанияПолей.Добавить(ОписаниеПоля); + + КонецЦикла; + + Возврат ОписанияПолей; + +КонецФункции + +Процедура ПриСозданииОбъекта() + + КонтейнерАннотаций = Новый КонтейнерАннотаций; + КонтейнерАннотаций.ДобавитьАннотацию(Тип("АннотацияЗначениеПоУмолчанию")); + КонтейнерАннотаций.ДобавитьАннотацию(Тип("АннотацияСиноним")); + +КонецПроцедуры + +Лог = Логирование.ПолучитьЛог("oscript.lib.configor.dto"); diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\227\320\275\320\260\321\207\320\265\320\275\320\270\320\265\320\237\320\276\320\243\320\274\320\276\320\273\321\207\320\260\320\275\320\270\321\216.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\227\320\275\320\260\321\207\320\265\320\275\320\270\320\265\320\237\320\276\320\243\320\274\320\276\320\273\321\207\320\260\320\275\320\270\321\216.os" new file mode 100644 index 0000000..11e00fe --- /dev/null +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\227\320\275\320\260\321\207\320\265\320\275\320\270\320\265\320\237\320\276\320\243\320\274\320\276\320\273\321\207\320\260\320\275\320\270\321\216.os" @@ -0,0 +1,24 @@ +Перем _Значение; + +// Возвращает имя аннотации +// +// Возвращаемое значение: +// Строка - имя аннотации +// +Функция ИмяАннотации() Экспорт + Возврат "ЗначениеПоУмолчанию"; +КонецФункции + +// Возвращает значение по умолчанию +// +// Возвращаемое значение: +// Произвольный - значение по умолчанию +// +Функция Значение() Экспорт + Возврат _Значение; +КонецФункции + +&Аннотация("ЗначениеПоУмолчанию") +Процедура ПриСозданииОбъекта(Значение) Экспорт + _Значение = Значение; +КонецПроцедуры diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\241\320\270\320\275\320\276\320\275\320\270\320\274.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\241\320\270\320\275\320\276\320\275\320\270\320\274.os" new file mode 100644 index 0000000..133c89b --- /dev/null +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\241\320\270\320\275\320\276\320\275\320\270\320\274.os" @@ -0,0 +1,24 @@ +Перем _Синоним; + +// Возвращает имя аннотации +// +// Возвращаемое значение: +// Строка - имя аннотации +// +Функция ИмяАннотации() Экспорт + Возврат "Синоним"; +КонецФункции + +// Возвращает синоним (альтернативное имя ключа в конфигурации) +// +// Возвращаемое значение: +// Строка - синоним свойства +// +Функция Синоним() Экспорт + Возврат _Синоним; +КонецФункции + +&Аннотация("Синоним") +Процедура ПриСозданииОбъекта(Значение) Экспорт + _Синоним = Значение; +КонецПроцедуры diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\276\320\262.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\276\320\262.os" index 7ee8028..791702e 100644 --- "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\276\320\262.os" +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\276\320\262.os" @@ -22,6 +22,9 @@ Перем ВнутреннийКонструкторПараметров; // Класс КонструкторПараметров Перем ИспользуетсяКонструкторПараметров; // булево +Перем ВнутреннийОписательДТО; // Класс ОписательДТО +Перем РеестрКлассовПараметров; // Соответствие: Префикс -> ОписанияПолей (Массив ОписаниеПоляДТО) + Перем Лог; // Логгер #Область Экспортных_процедур @@ -307,6 +310,71 @@ КонецФункции +// Регистрирует класс DTO-параметров по префиксу +// Считывает аннотации свойств класса и сохраняет описания полей +// +// Параметры: +// КлассОбъект - Объект - экземпляр DTO-класса с аннотированными свойствами +// Префикс - Строка - ключ верхнего уровня в конфигурации +// +Процедура ЗарегистрироватьКлассПараметров(Знач КлассОбъект, Знач Префикс) Экспорт + + Если ВнутреннийОписательДТО = Неопределено Тогда + ВнутреннийОписательДТО = Новый ОписательДТО; + КонецЕсли; + + ОписанияПолей = ВнутреннийОписательДТО.ОписатьКласс(КлассОбъект); + + Лог.Отладка("Зарегистрирован класс параметров с префиксом <%1>, полей: %2", Префикс, ОписанияПолей.Количество()); + + РеестрКлассовПараметров.Вставить(Префикс, ОписанияПолей); + +КонецПроцедуры + +// Заполняет свойства объекта DTO из прочитанных параметров +// Использует зарегистрированные описания полей для маппинга +// +// Параметры: +// КлассОбъект - Объект - экземпляр DTO-класса для заполнения +// Префикс - Строка - ключ верхнего уровня в конфигурации +// +Процедура ЗаполнитьОбъектПараметров(Знач КлассОбъект, Знач Префикс) Экспорт + + ОписанияПолей = РеестрКлассовПараметров[Префикс]; + + Если ОписанияПолей = Неопределено Тогда + ВызватьИсключение "Класс параметров с префиксом """ + Префикс + """ не зарегистрирован"; + КонецЕсли; + + ОбъектРефлектор = Новый Рефлектор; + + Для Каждого ОписаниеПоля Из ОписанияПолей Цикл + + КлючКонфигурации = ОписаниеПоля.КлючКонфигурации(); + ПолныйКлюч = Префикс + "." + КлючКонфигурации; + + ЗначениеИзКонфига = Параметр(ПолныйКлюч); + + Если Не ЗначениеИзКонфига = Неопределено Тогда + + Лог.Отладка("Установка свойства <%1> из параметра <%2>", ОписаниеПоля.Имя, ПолныйКлюч); + ОбъектРефлектор.УстановитьСвойство(КлассОбъект, ОписаниеПоля.Имя, ЗначениеИзКонфига); + + ИначеЕсли Не ОписаниеПоля.Обязательное Тогда + + Лог.Отладка("Свойство <%1> не найдено в конфиге, используется значение по умолчанию", ОписаниеПоля.Имя); + ОбъектРефлектор.УстановитьСвойство(КлассОбъект, ОписаниеПоля.Имя, ОписаниеПоля.ЗначениеПоУмолчанию); + + Иначе + + ВызватьИсключение "Обязательный параметр """ + ПолныйКлюч + """ (свойство """ + ОписаниеПоля.Имя + """) не задан в конфигурации и не имеет значения по умолчанию"; + + КонецЕсли; + + КонецЦикла; + +КонецПроцедуры + #КонецОбласти #Область Вспомогательные_процедуры_и_функции @@ -478,6 +546,9 @@ ВнутреннийКонструкторПараметров = Неопределено; ИспользуетсяКонструкторПараметров = Ложь; + ВнутреннийОписательДТО = Неопределено; + РеестрКлассовПараметров = Новый Соответствие; + КонецПроцедуры Функция ИнтерфейсРеализован(Интерфейс, КлассОбъект, ВыдатьОшибку = Ложь) diff --git "a/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236.os" "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236.os" new file mode 100644 index 0000000..524bf55 --- /dev/null +++ "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236.os" @@ -0,0 +1,10 @@ +// Тестовый DTO с аннотированными свойствами для проверки ОписательДТО и МенеджерПараметров + +&ЗначениеПоУмолчанию("localhost") +Перем АдресСервера Экспорт; + +&ЗначениеПоУмолчанию(8080) +Перем ПортСервера Экспорт; + +Процедура ПриСозданииОбъекта() +КонецПроцедуры diff --git "a/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\241\320\236\320\261\321\217\320\267\320\260\321\202\320\265\320\273\321\214\320\275\321\213\320\274\320\237\320\276\320\273\320\265\320\274.os" "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\241\320\236\320\261\321\217\320\267\320\260\321\202\320\265\320\273\321\214\320\275\321\213\320\274\320\237\320\276\320\273\320\265\320\274.os" new file mode 100644 index 0000000..07564fb --- /dev/null +++ "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\241\320\236\320\261\321\217\320\267\320\260\321\202\320\265\320\273\321\214\320\275\321\213\320\274\320\237\320\276\320\273\320\265\320\274.os" @@ -0,0 +1,9 @@ +// Тестовый DTO с обязательным полем (без ЗначениеПоУмолчанию) + +&ЗначениеПоУмолчанию("localhost") +Перем АдресСервера Экспорт; + +Перем ОбязательноеПоле Экспорт; + +Процедура ПриСозданииОбъекта() +КонецПроцедуры diff --git "a/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\241\320\241\320\270\320\275\320\276\320\275\320\270\320\274\320\276\320\274.os" "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\241\320\241\320\270\320\275\320\276\320\275\320\270\320\274\320\276\320\274.os" new file mode 100644 index 0000000..47a527a --- /dev/null +++ "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\241\320\241\320\270\320\275\320\276\320\275\320\270\320\274\320\276\320\274.os" @@ -0,0 +1,8 @@ +// Тестовый DTO с синонимом свойства + +&Синоним("port") +&ЗначениеПоУмолчанию(8080) +Перем Порт Экспорт; + +Процедура ПриСозданииОбъекта() +КонецПроцедуры diff --git "a/tests/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236_test.os" "b/tests/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236_test.os" new file mode 100644 index 0000000..0380445 --- /dev/null +++ "b/tests/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236_test.os" @@ -0,0 +1,164 @@ +#использовать "../" +#Использовать asserts +#Использовать tempfiles + +Перем юТест; +Перем КаталогФикстур; + +Функция ПолучитьСписокТестов(Знач Тестирование) Экспорт + + юТест = Тестирование; + + КаталогФикстур = ОбъединитьПути(ТекущийСценарий().Каталог, "fixtures"); + + ИменаТестов = Новый Массив; + + ИменаТестов.Добавить("ТестДолжен_ОписатьКлассЧитаетАннотацииСвойств"); + ИменаТестов.Добавить("ТестДолжен_ОписатьКлассОпределяетОбязательныеПоля"); + ИменаТестов.Добавить("ТестДолжен_ОписатьКлассЧитаетСинонимы"); + ИменаТестов.Добавить("ТестДолжен_ЗарегистрироватьИЗаполнитьДТОИзКонфига"); + ИменаТестов.Добавить("ТестДолжен_ПрименитьЗначенияПоУмолчаниюПриОтсутствииКлюча"); + ИменаТестов.Добавить("ТестДолжен_ВыброситьИсключениеПриОтсутствииОбязательногоПоля"); + ИменаТестов.Добавить("ТестДолжен_ИспользоватьСинонимПриЗаполнении"); + + Возврат ИменаТестов; + +КонецФункции + +Функция ЗагрузитьДТО(Знач ИмяФайла) + Возврат ЗагрузитьСценарий(ОбъединитьПути(КаталогФикстур, ИмяФайла)); +КонецФункции + +// КП-1.1: ОписательДТО читает аннотации свойств +Процедура ТестДолжен_ОписатьКлассЧитаетАннотацииСвойств() Экспорт + + ДТО = ЗагрузитьДТО("ТестовыйДТО.os"); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "Тест"); + +КонецПроцедуры + +// КП-1.2: ОписательДТО определяет обязательные поля +Процедура ТестДолжен_ОписатьКлассОпределяетОбязательныеПоля() Экспорт + + ДТО = ЗагрузитьДТО("ТестовыйДТОСОбязательнымПолем.os"); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "Тест"); + +КонецПроцедуры + +// КП-1.3: Синонимы +Процедура ТестДолжен_ОписатьКлассЧитаетСинонимы() Экспорт + + ДТО = ЗагрузитьДТО("ТестовыйДТОССинонимом.os"); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "Тест"); + +КонецПроцедуры + +// КП-1.4: Регистрация и заполнение DTO из конфига +Процедура ТестДолжен_ЗарегистрироватьИЗаполнитьДТОИзКонфига() Экспорт + + ДТО = ЗагрузитьДТО("ТестовыйДТО.os"); + + ВременныйФайл = ПолучитьВременныйФайлJSON( + "{""Префикс"": {""АдресСервера"": ""prod-server"", ""ПортСервера"": 3306}}" + ); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ИспользоватьПровайдерJSON(); + Менеджер.УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "Префикс"); + Менеджер.Прочитать(); + Менеджер.ЗаполнитьОбъектПараметров(ДТО, "Префикс"); + + Ожидаем.Что(ДТО.АдресСервера, "АдресСервера должен быть из конфига").Равно("prod-server"); + Ожидаем.Что(ДТО.ПортСервера, "ПортСервера должен быть из конфига").Равно(3306); + + УдалитьФайлы(ВременныйФайл); + +КонецПроцедуры + +// КП-1.5: Значения по умолчанию при отсутствии ключа +Процедура ТестДолжен_ПрименитьЗначенияПоУмолчаниюПриОтсутствииКлюча() Экспорт + + ДТО = ЗагрузитьДТО("ТестовыйДТО.os"); + + ВременныйФайл = ПолучитьВременныйФайлJSON( + "{""Префикс"": {""АдресСервера"": ""prod-server""}}" + ); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ИспользоватьПровайдерJSON(); + Менеджер.УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "Префикс"); + Менеджер.Прочитать(); + Менеджер.ЗаполнитьОбъектПараметров(ДТО, "Префикс"); + + Ожидаем.Что(ДТО.АдресСервера, "АдресСервера должен быть из конфига").Равно("prod-server"); + Ожидаем.Что(ДТО.ПортСервера, "ПортСервера должен быть дефолтным").Равно(8080); + + УдалитьФайлы(ВременныйФайл); + +КонецПроцедуры + +// КП-1.6: Обязательное поле без значения — исключение +Процедура ТестДолжен_ВыброситьИсключениеПриОтсутствииОбязательногоПоля() Экспорт + + ДТО = ЗагрузитьДТО("ТестовыйДТОСОбязательнымПолем.os"); + + ВременныйФайл = ПолучитьВременныйФайлJSON( + "{""Префикс"": {""АдресСервера"": ""prod-server""}}" + ); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ИспользоватьПровайдерJSON(); + Менеджер.УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "Префикс"); + Менеджер.Прочитать(); + + Попытка + Менеджер.ЗаполнитьОбъектПараметров(ДТО, "Префикс"); + Ожидаем.Что(Ложь, "Ожидалось исключение для обязательного поля").Равно(Истина); + Исключение + Ожидаем.Что(ОписаниеОшибки()).Содержит("ОбязательноеПоле"); + КонецПопытки; + + УдалитьФайлы(ВременныйФайл); + +КонецПроцедуры + +// КП-1.7: Синоним при заполнении +Процедура ТестДолжен_ИспользоватьСинонимПриЗаполнении() Экспорт + + ДТО = ЗагрузитьДТО("ТестовыйДТОССинонимом.os"); + + ВременныйФайл = ПолучитьВременныйФайлJSON( + "{""Префикс"": {""port"": 3306}}" + ); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ИспользоватьПровайдерJSON(); + Менеджер.УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "Префикс"); + Менеджер.Прочитать(); + Менеджер.ЗаполнитьОбъектПараметров(ДТО, "Префикс"); + + Ожидаем.Что(ДТО.Порт, "Порт должен быть заполнен из конфига по синониму port").Равно(3306); + + УдалитьФайлы(ВременныйФайл); + +КонецПроцедуры + +Функция ПолучитьВременныйФайлJSON(Знач СодержимоеJSON) + + ВременныйФайл = ПолучитьИмяВременногоФайла("json"); + ЗаписьТекста = Новый ЗаписьТекста(ВременныйФайл, "UTF-8"); + ЗаписьТекста.Записать(СодержимоеJSON); + ЗаписьТекста.Закрыть(); + Возврат ВременныйФайл; + +КонецФункции From efa50db5f9c5c1af183611a2ab7d7afe3284c0b5 Mon Sep 17 00:00:00 2001 From: Egor Ivanov Date: Sat, 11 Apr 2026 00:34:36 +0300 Subject: [PATCH 02/13] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=B2=D0=B5=D1=80=D1=81=D0=B8=D1=8F=20?= =?UTF-8?q?=D0=BF=D0=B0=D0=BA=D0=B5=D1=82=D0=B0=20=D0=B4=D0=BE=200.12.0=20?= =?UTF-8?q?=D0=B2=20=D1=84=D0=B0=D0=B9=D0=BB=D0=B5=20packagedef?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packagedef | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packagedef b/packagedef index b8cd2cf..ca63b73 100644 --- a/packagedef +++ b/packagedef @@ -4,7 +4,7 @@ // Описание.Имя("configor") - .Версия("0.11.1") + .Версия("0.12.0") .Автор("Khorev Aleksey") .АдресАвтора("Khorevaa@gmail.com") .Описание("Библиотека для работы с конфигурационными файлами в формате json, yaml") From 5a62918b17740944d94bcdc3a15d97e2845d1ac7 Mon Sep 17 00:00:00 2001 From: Egor Ivanov Date: Sat, 11 Apr 2026 00:56:25 +0300 Subject: [PATCH 03/13] =?UTF-8?q?=D1=82=D0=B5=D1=81=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...3\321\214\320\224\320\242\320\236_test.os" | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git "a/tests/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236_test.os" "b/tests/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236_test.os" index 0380445..3e91c73 100644 --- "a/tests/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236_test.os" +++ "b/tests/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236_test.os" @@ -32,31 +32,73 @@ // КП-1.1: ОписательДТО читает аннотации свойств Процедура ТестДолжен_ОписатьКлассЧитаетАннотацииСвойств() Экспорт + // Arrange ДТО = ЗагрузитьДТО("ТестовыйДТО.os"); + ВременныйФайл = ПолучитьВременныйФайлJSON("{""Тест"": {}}"); Менеджер = Новый МенеджерПараметров; + Менеджер.ИспользоватьПровайдерJSON(); + Менеджер.УстановитьФайлПараметров(ВременныйФайл); Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "Тест"); + // Act + Менеджер.Прочитать(); + Менеджер.ЗаполнитьОбъектПараметров(ДТО, "Тест"); + + // Assert + Ожидаем.Что(ДТО.АдресСервера, "Аннотация ЗначениеПоУмолчанию должна быть прочитана для АдресСервера").Равно("localhost"); + Ожидаем.Что(ДТО.ПортСервера, "Аннотация ЗначениеПоУмолчанию должна быть прочитана для ПортСервера").Равно(8080); + + УдалитьФайлы(ВременныйФайл); + КонецПроцедуры // КП-1.2: ОписательДТО определяет обязательные поля Процедура ТестДолжен_ОписатьКлассОпределяетОбязательныеПоля() Экспорт + // Arrange ДТО = ЗагрузитьДТО("ТестовыйДТОСОбязательнымПолем.os"); + ВременныйФайл = ПолучитьВременныйФайлJSON("{""Тест"": {""АдресСервера"": ""test""}}"); Менеджер = Новый МенеджерПараметров; + Менеджер.ИспользоватьПровайдерJSON(); + Менеджер.УстановитьФайлПараметров(ВременныйФайл); Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "Тест"); + Менеджер.Прочитать(); + + // Act + Assert + Попытка + Менеджер.ЗаполнитьОбъектПараметров(ДТО, "Тест"); + Ожидаем.Что(Ложь, "Ожидалось исключение для обязательного поля").Равно(Истина); + Исключение + Ожидаем.Что(ОписаниеОшибки()).Содержит("ОбязательноеПоле"); + КонецПопытки; + + УдалитьФайлы(ВременныйФайл); КонецПроцедуры // КП-1.3: Синонимы Процедура ТестДолжен_ОписатьКлассЧитаетСинонимы() Экспорт + // Arrange ДТО = ЗагрузитьДТО("ТестовыйДТОССинонимом.os"); + ВременныйФайл = ПолучитьВременныйФайлJSON("{""Тест"": {""port"": 3306}}"); Менеджер = Новый МенеджерПараметров; + Менеджер.ИспользоватьПровайдерJSON(); + Менеджер.УстановитьФайлПараметров(ВременныйФайл); Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "Тест"); + // Act + Менеджер.Прочитать(); + Менеджер.ЗаполнитьОбъектПараметров(ДТО, "Тест"); + + // Assert + Ожидаем.Что(ДТО.Порт, "Синоним port должен быть прочитан из аннотации").Равно(3306); + + УдалитьФайлы(ВременныйФайл); + КонецПроцедуры // КП-1.4: Регистрация и заполнение DTO из конфига From 5deabb88dbbfb4892d0cb8ccf3025c5282820586 Mon Sep 17 00:00:00 2001 From: Egor Ivanov Date: Sat, 11 Apr 2026 01:31:59 +0300 Subject: [PATCH 04/13] =?UTF-8?q?=D0=92=D0=BB=D0=BE=D0=B6=D0=B5=D0=BD?= =?UTF-8?q?=D0=BD=D1=8B=D0=B5=20=D0=94=D0=A2=D0=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...20\273\321\217\320\224\320\242\320\236.os" | 21 ++++ ...20\273\321\214\320\224\320\242\320\236.os" | 36 ++++++ ...21\213\320\271\320\224\320\242\320\236.os" | 24 ++++ ...20\265\321\202\321\200\320\276\320\262.os" | 69 +++++++++-- ...21\207\320\265\320\275\320\270\320\265.os" | 10 ++ ...20\260\320\275\320\275\321\213\321\205.os" | 10 ++ ...21\202\320\260\321\206\320\270\321\217.os" | 12 ++ ...20\266\320\265\320\275\320\270\320\265.os" | 13 ++ ...21\201\320\270\320\262\320\276\320\274.os" | 10 ++ ...3\321\214\320\224\320\242\320\236_test.os" | 116 ++++++++++++++++++ 10 files changed, 312 insertions(+), 9 deletions(-) create mode 100644 "src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\222\320\273\320\276\320\266\320\265\320\275\320\275\321\213\320\271\320\224\320\242\320\236.os" create mode 100644 "tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\320\276\320\265\320\237\320\276\320\264\320\272\320\273\321\216\321\207\320\265\320\275\320\270\320\265.os" create mode 100644 "tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\221\320\260\320\267\320\260\320\224\320\260\320\275\320\275\321\213\321\205.os" create mode 100644 "tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\221\320\260\320\267\320\260\320\224\320\260\320\275\320\275\321\213\321\205\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217.os" create mode 100644 "tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\320\265.os" create mode 100644 "tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\241\320\234\320\260\321\201\321\201\320\270\320\262\320\276\320\274.os" diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265\320\237\320\276\320\273\321\217\320\224\320\242\320\236.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265\320\237\320\276\320\273\321\217\320\224\320\242\320\236.os" index 5ab56c9..313d4d7 100644 --- "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265\320\237\320\276\320\273\321\217\320\224\320\242\320\236.os" +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265\320\237\320\276\320\273\321\217\320\224\320\242\320\236.os" @@ -5,6 +5,8 @@ Перем ЗначениеПоУмолчанию Экспорт; // Произвольный - значение по умолчанию Перем Синоним Экспорт; // Строка - альтернативное имя ключа в конфигурации Перем Обязательное Экспорт; // Булево - признак обязательности (нет ЗначениеПоУмолчанию) +Перем ВложенныйОбъект Экспорт; // Объект - ссылка на вложенный DTO-объект (Неопределено если примитив) +Перем ОписанияВложенныхПолей Экспорт; // Массив из ОписаниеПоляДТО - описания полей вложенного DTO // Конструктор описания поля // @@ -18,6 +20,8 @@ ЗначениеПоУмолчанию = Неопределено; Синоним = Неопределено; Обязательное = Истина; + ВложенныйОбъект = Неопределено; + ОписанияВложенныхПолей = Неопределено; КонецПроцедуры @@ -46,6 +50,23 @@ Синоним = НовыйСиноним; КонецПроцедуры +// Устанавливает вложенный DTO-объект и его описания полей +// +// Параметры: +// Объект - Объект - вложенный DTO-объект +// ОписанияПолей - Массив из ОписаниеПоляДТО - описания полей вложенного DTO +// +Процедура УстановитьВложенныйОбъект(Знач Объект, Знач ОписанияПолей) Экспорт + ВложенныйОбъект = Объект; + ОписанияВложенныхПолей = ОписанияПолей; + Обязательное = Ложь; +КонецПроцедуры + +// Возвращает признак того, что поле является вложенным DTO +Функция ЭтоВложенныйДТО() Экспорт + Возврат Не ВложенныйОбъект = Неопределено; +КонецФункции + // Возвращает ключ для поиска в конфигурации // Если задан синоним — возвращает его, иначе — имя свойства // diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236.os" index 52fa3e3..7b1543a 100644 --- "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236.os" +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236.os" @@ -47,10 +47,45 @@ ОписаниеПоля.УстановитьСиноним(ОбъектАннотации.Синоним()); + ИначеЕсли ИмяАннотации = "ВЛОЖЕННЫЙДТО" Тогда + + ВложенныйОбъект = Новый(ОбъектАннотации.ИмяКласса()); + ВложенныеОписания = ОписатьКласс(ВложенныйОбъект); + ОписаниеПоля.УстановитьВложенныйОбъект(ВложенныйОбъект, ВложенныеОписания); + + СтандартныйРефлектор = Новый Рефлектор; + СтандартныйРефлектор.УстановитьСвойство(КлассОбъект, Свойство.Имя, ВложенныйОбъект); + КонецЕсли; КонецЦикла; + // Проверяем, является ли текущее значение свойства вложенным DTO-объектом + // (если аннотация &ВложенныйДТО не была задана явно) + Если Не ОписаниеПоля.ЭтоВложенныйДТО() Тогда + Попытка + СтандартныйРефлектор = Новый Рефлектор; + ЗначениеСвойства = СтандартныйРефлектор.ПолучитьСвойство(КлассОбъект, Свойство.Имя); + Если Не ЗначениеСвойства = Неопределено Тогда + ВложенныйРефлектор = Новый РефлекторОбъекта(ЗначениеСвойства); + ВложенныеСвойства = ВложенныйРефлектор.ПолучитьТаблицуСвойств(Неопределено, Истина); + ЕстьЭкспортныеСвойства = Ложь; + Для Каждого ВлСвойство Из ВложенныеСвойства Цикл + Если ВлСвойство.Экспорт Тогда + ЕстьЭкспортныеСвойства = Истина; + Прервать; + КонецЕсли; + КонецЦикла; + Если ЕстьЭкспортныеСвойства Тогда + ВложенныеОписания = ОписатьКласс(ЗначениеСвойства); + ОписаниеПоля.УстановитьВложенныйОбъект(ЗначениеСвойства, ВложенныеОписания); + КонецЕсли; + КонецЕсли; + Исключение + // Значение недоступно или не является объектом — пропускаем + КонецПопытки; + КонецЕсли; + ОписанияПолей.Добавить(ОписаниеПоля); КонецЦикла; @@ -64,6 +99,7 @@ КонтейнерАннотаций = Новый КонтейнерАннотаций; КонтейнерАннотаций.ДобавитьАннотацию(Тип("АннотацияЗначениеПоУмолчанию")); КонтейнерАннотаций.ДобавитьАннотацию(Тип("АннотацияСиноним")); + КонтейнерАннотаций.ДобавитьАннотацию(Тип("АннотацияВложенныйДТО")); КонецПроцедуры diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\222\320\273\320\276\320\266\320\265\320\275\320\275\321\213\320\271\320\224\320\242\320\236.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\222\320\273\320\276\320\266\320\265\320\275\320\275\321\213\320\271\320\224\320\242\320\236.os" new file mode 100644 index 0000000..c8b894f --- /dev/null +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\222\320\273\320\276\320\266\320\265\320\275\320\275\321\213\320\271\320\224\320\242\320\236.os" @@ -0,0 +1,24 @@ +Перем _ИмяКласса; + +// Возвращает имя аннотации +// +// Возвращаемое значение: +// Строка - имя аннотации +// +Функция ИмяАннотации() Экспорт + Возврат "ВложенныйДТО"; +КонецФункции + +// Возвращает имя класса вложенного DTO +// +// Возвращаемое значение: +// Строка - имя класса +// +Функция ИмяКласса() Экспорт + Возврат _ИмяКласса; +КонецФункции + +&Аннотация("ВложенныйДТО") +Процедура ПриСозданииОбъекта(ИмяКласса) Экспорт + _ИмяКласса = ИмяКласса; +КонецПроцедуры diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\276\320\262.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\276\320\262.os" index 791702e..450f7a2 100644 --- "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\276\320\262.os" +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\276\320\262.os" @@ -353,21 +353,30 @@ КлючКонфигурации = ОписаниеПоля.КлючКонфигурации(); ПолныйКлюч = Префикс + "." + КлючКонфигурации; - ЗначениеИзКонфига = Параметр(ПолныйКлюч); + Если ОписаниеПоля.ЭтоВложенныйДТО() Тогда - Если Не ЗначениеИзКонфига = Неопределено Тогда + Лог.Отладка("Рекурсивное заполнение вложенного DTO <%1> по ключу <%2>", ОписаниеПоля.Имя, ПолныйКлюч); + ЗаполнитьВложенныйДТО(ОписаниеПоля, ПолныйКлюч); - Лог.Отладка("Установка свойства <%1> из параметра <%2>", ОписаниеПоля.Имя, ПолныйКлюч); - ОбъектРефлектор.УстановитьСвойство(КлассОбъект, ОписаниеПоля.Имя, ЗначениеИзКонфига); + Иначе - ИначеЕсли Не ОписаниеПоля.Обязательное Тогда + ЗначениеИзКонфига = Параметр(ПолныйКлюч); - Лог.Отладка("Свойство <%1> не найдено в конфиге, используется значение по умолчанию", ОписаниеПоля.Имя); - ОбъектРефлектор.УстановитьСвойство(КлассОбъект, ОписаниеПоля.Имя, ОписаниеПоля.ЗначениеПоУмолчанию); + Если Не ЗначениеИзКонфига = Неопределено Тогда - Иначе + Лог.Отладка("Установка свойства <%1> из параметра <%2>", ОписаниеПоля.Имя, ПолныйКлюч); + ОбъектРефлектор.УстановитьСвойство(КлассОбъект, ОписаниеПоля.Имя, ЗначениеИзКонфига); + + ИначеЕсли Не ОписаниеПоля.Обязательное Тогда + + Лог.Отладка("Свойство <%1> не найдено в конфиге, используется значение по умолчанию", ОписаниеПоля.Имя); + ОбъектРефлектор.УстановитьСвойство(КлассОбъект, ОписаниеПоля.Имя, ОписаниеПоля.ЗначениеПоУмолчанию); - ВызватьИсключение "Обязательный параметр """ + ПолныйКлюч + """ (свойство """ + ОписаниеПоля.Имя + """) не задан в конфигурации и не имеет значения по умолчанию"; + Иначе + + ВызватьИсключение "Обязательный параметр """ + ПолныйКлюч + """ (свойство """ + ОписаниеПоля.Имя + """) не задан в конфигурации и не имеет значения по умолчанию"; + + КонецЕсли; КонецЕсли; @@ -379,6 +388,48 @@ #Область Вспомогательные_процедуры_и_функции +Процедура ЗаполнитьВложенныйДТО(Знач ОписаниеПоля, Знач Префикс) + + ВложенныйОбъект = ОписаниеПоля.ВложенныйОбъект; + ВложенныеОписания = ОписаниеПоля.ОписанияВложенныхПолей; + ОбъектРефлектор = Новый Рефлектор; + + Для Каждого ВложенноеОписание Из ВложенныеОписания Цикл + + ВложенныйКлюч = ВложенноеОписание.КлючКонфигурации(); + ПолныйКлюч = Префикс + "." + ВложенныйКлюч; + + Если ВложенноеОписание.ЭтоВложенныйДТО() Тогда + + Лог.Отладка("Рекурсивное заполнение вложенного DTO <%1> по ключу <%2>", ВложенноеОписание.Имя, ПолныйКлюч); + ЗаполнитьВложенныйДТО(ВложенноеОписание, ПолныйКлюч); + + Иначе + + ЗначениеИзКонфига = Параметр(ПолныйКлюч); + + Если Не ЗначениеИзКонфига = Неопределено Тогда + + Лог.Отладка("Установка вложенного свойства <%1> из параметра <%2>", ВложенноеОписание.Имя, ПолныйКлюч); + ОбъектРефлектор.УстановитьСвойство(ВложенныйОбъект, ВложенноеОписание.Имя, ЗначениеИзКонфига); + + ИначеЕсли Не ВложенноеОписание.Обязательное Тогда + + Лог.Отладка("Вложенное свойство <%1> не найдено в конфиге, используется значение по умолчанию", ВложенноеОписание.Имя); + ОбъектРефлектор.УстановитьСвойство(ВложенныйОбъект, ВложенноеОписание.Имя, ВложенноеОписание.ЗначениеПоУмолчанию); + + Иначе + + ВызватьИсключение "Обязательный параметр """ + ПолныйКлюч + """ (свойство """ + ВложенноеОписание.Имя + """) не задан в конфигурации и не имеет значения по умолчанию"; + + КонецЕсли; + + КонецЕсли; + + КонецЦикла; + +КонецПроцедуры + Функция ПолучитьКонструкторПараметров() Конструктор = Новый КонструкторПараметров(); diff --git "a/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\320\276\320\265\320\237\320\276\320\264\320\272\320\273\321\216\321\207\320\265\320\275\320\270\320\265.os" "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\320\276\320\265\320\237\320\276\320\264\320\272\320\273\321\216\321\207\320\265\320\275\320\270\320\265.os" new file mode 100644 index 0000000..1254f93 --- /dev/null +++ "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\320\276\320\265\320\237\320\276\320\264\320\272\320\273\321\216\321\207\320\265\320\275\320\270\320\265.os" @@ -0,0 +1,10 @@ +// Вложенный DTO: параметры подключения + +&ЗначениеПоУмолчанию("localhost") +Перем Хост Экспорт; + +&ЗначениеПоУмолчанию(5432) +Перем Порт Экспорт; + +Процедура ПриСозданииОбъекта() +КонецПроцедуры diff --git "a/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\221\320\260\320\267\320\260\320\224\320\260\320\275\320\275\321\213\321\205.os" "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\221\320\260\320\267\320\260\320\224\320\260\320\275\320\275\321\213\321\205.os" new file mode 100644 index 0000000..f4292f6 --- /dev/null +++ "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\221\320\260\320\267\320\260\320\224\320\260\320\275\320\275\321\213\321\205.os" @@ -0,0 +1,10 @@ +// DTO второго уровня: настройки базы данных с вложенным DTO подключения + +&ЗначениеПоУмолчанию("main_db") +Перем ИмяБазы Экспорт; + +Перем Подключение Экспорт; + +Процедура ПриСозданииОбъекта() + Подключение = ЗагрузитьСценарий(ОбъединитьПути(ТекущийСценарий().Каталог, "ТестовоеПодключение.os")); +КонецПроцедуры diff --git "a/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\221\320\260\320\267\320\260\320\224\320\260\320\275\320\275\321\213\321\205\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217.os" "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\221\320\260\320\267\320\260\320\224\320\260\320\275\320\275\321\213\321\205\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217.os" new file mode 100644 index 0000000..2c8f717 --- /dev/null +++ "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\221\320\260\320\267\320\260\320\224\320\260\320\275\320\275\321\213\321\205\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217.os" @@ -0,0 +1,12 @@ +// DTO второго уровня: то же самое, что ТестовыйДТОБазаДанных, +// но вложенный DTO указан через аннотацию &ВложенныйДТО вместо Новый в конструкторе. + +&ЗначениеПоУмолчанию("main_db") +Перем ИмяБазы Экспорт; + +&ВложенныйДТО("ТестовоеПодключение") +Перем Подключение Экспорт; + +Процедура ПриСозданииОбъекта() + +КонецПроцедуры diff --git "a/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\320\265.os" "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\320\265.os" new file mode 100644 index 0000000..b66341e --- /dev/null +++ "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\320\265.os" @@ -0,0 +1,13 @@ +// DTO верхнего уровня: конфигурация приложения с вложенными DTO + +&ЗначениеПоУмолчанию("MyApp") +Перем Название Экспорт; + +&ЗначениеПоУмолчанию("1.0.0") +Перем Версия Экспорт; + +Перем БазаДанных Экспорт; + +Процедура ПриСозданииОбъекта() + БазаДанных = ЗагрузитьСценарий(ОбъединитьПути(ТекущийСценарий().Каталог, "ТестовыйДТОБазаДанных.os")); +КонецПроцедуры diff --git "a/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\241\320\234\320\260\321\201\321\201\320\270\320\262\320\276\320\274.os" "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\241\320\234\320\260\321\201\321\201\320\270\320\262\320\276\320\274.os" new file mode 100644 index 0000000..49e9140 --- /dev/null +++ "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\241\320\234\320\260\321\201\321\201\320\270\320\262\320\276\320\274.os" @@ -0,0 +1,10 @@ +// DTO с массивом вложенных объектов + +&ЗначениеПоУмолчанию("cluster") +Перем Имя Экспорт; + +Перем Узлы Экспорт; + +Процедура ПриСозданииОбъекта() + Узлы = Новый Массив; +КонецПроцедуры diff --git "a/tests/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236_test.os" "b/tests/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236_test.os" index 3e91c73..48105e0 100644 --- "a/tests/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236_test.os" +++ "b/tests/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236_test.os" @@ -20,6 +20,10 @@ ИменаТестов.Добавить("ТестДолжен_ПрименитьЗначенияПоУмолчаниюПриОтсутствииКлюча"); ИменаТестов.Добавить("ТестДолжен_ВыброситьИсключениеПриОтсутствииОбязательногоПоля"); ИменаТестов.Добавить("ТестДолжен_ИспользоватьСинонимПриЗаполнении"); + ИменаТестов.Добавить("ТестДолжен_ЗаполнитьВложенныйДТО"); + ИменаТестов.Добавить("ТестДолжен_ЗаполнитьДвухуровневыйДТО"); + ИменаТестов.Добавить("ТестДолжен_ПрименитьУмолчанияВоВложенномДТО"); + ИменаТестов.Добавить("ТестДолжен_ОбработатьМассивВоВложенномДТО"); Возврат ИменаТестов; @@ -195,6 +199,118 @@ КонецПроцедуры +// КП-2.1: Вложенный DTO — БазаДанных.Подключение +Процедура ТестДолжен_ЗаполнитьВложенныйДТО() Экспорт + + // Arrange + ДТО = ЗагрузитьДТО("ТестовыйДТОБазаДанных.os"); + ВременныйФайл = ПолучитьВременныйФайлJSON( + "{""БД"": {""ИмяБазы"": ""test_db"", ""Подключение"": {""Хост"": ""db-server"", ""Порт"": 3306}}}" + ); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ИспользоватьПровайдерJSON(); + Менеджер.УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "БД"); + + // Act + Менеджер.Прочитать(); + Менеджер.ЗаполнитьОбъектПараметров(ДТО, "БД"); + + // Assert + Ожидаем.Что(ДТО.ИмяБазы, "ИмяБазы должно быть из конфига").Равно("test_db"); + Ожидаем.Что(ДТО.Подключение.Хост, "Вложенный Хост должен быть заполнен из конфига").Равно("db-server"); + Ожидаем.Что(ДТО.Подключение.Порт, "Вложенный Порт должен быть заполнен из конфига").Равно(3306); + + УдалитьФайлы(ВременныйФайл); + +КонецПроцедуры + +// КП-2.2: Трёхуровневый DTO — Приложение.БазаДанных.Подключение +Процедура ТестДолжен_ЗаполнитьДвухуровневыйДТО() Экспорт + + // Arrange + ДТО = ЗагрузитьДТО("ТестовыйДТОПриложение.os"); + ВременныйФайл = ПолучитьВременныйФайлJSON( + "{""Приложение"": {""Название"": ""SuperApp"", ""Версия"": ""2.0.0"", ""БазаДанных"": {""ИмяБазы"": ""prod_db"", ""Подключение"": {""Хост"": ""prod-host"", ""Порт"": 5432}}}}" + ); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ИспользоватьПровайдерJSON(); + Менеджер.УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "Приложение"); + + // Act + Менеджер.Прочитать(); + Менеджер.ЗаполнитьОбъектПараметров(ДТО, "Приложение"); + + // Assert + Ожидаем.Что(ДТО.Название, "Название должно быть из конфига").Равно("SuperApp"); + Ожидаем.Что(ДТО.Версия, "Версия должна быть из конфига").Равно("2.0.0"); + Ожидаем.Что(ДТО.БазаДанных.ИмяБазы, "Вложенное ИмяБазы должно быть из конфига").Равно("prod_db"); + Ожидаем.Что(ДТО.БазаДанных.Подключение.Хост, "Глубоко вложенный Хост должен быть из конфига").Равно("prod-host"); + Ожидаем.Что(ДТО.БазаДанных.Подключение.Порт, "Глубоко вложенный Порт должен быть из конфига").Равно(5432); + + УдалитьФайлы(ВременныйФайл); + +КонецПроцедуры + +// КП-2.3: Вложенный DTO — умолчания при отсутствии ключей во вложенной структуре +Процедура ТестДолжен_ПрименитьУмолчанияВоВложенномДТО() Экспорт + + // Arrange + ДТО = ЗагрузитьДТО("ТестовыйДТОБазаДанных.os"); + ВременныйФайл = ПолучитьВременныйФайлJSON( + "{""БД"": {""ИмяБазы"": ""custom_db""}}" + ); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ИспользоватьПровайдерJSON(); + Менеджер.УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "БД"); + + // Act + Менеджер.Прочитать(); + Менеджер.ЗаполнитьОбъектПараметров(ДТО, "БД"); + + // Assert + Ожидаем.Что(ДТО.ИмяБазы, "ИмяБазы должно быть из конфига").Равно("custom_db"); + Ожидаем.Что(ДТО.Подключение.Хост, "Вложенный Хост должен быть по умолчанию").Равно("localhost"); + Ожидаем.Что(ДТО.Подключение.Порт, "Вложенный Порт должен быть по умолчанию").Равно(5432); + + УдалитьФайлы(ВременныйФайл); + +КонецПроцедуры + +// КП-2.4: DTO с массивом во вложенной структуре +Процедура ТестДолжен_ОбработатьМассивВоВложенномДТО() Экспорт + + // Arrange + ДТО = ЗагрузитьДТО("ТестовыйДТОСМассивом.os"); + ВременныйФайл = ПолучитьВременныйФайлJSON( + "{""Кластер"": {""Имя"": ""prod-cluster"", ""Узлы"": [""node1"", ""node2"", ""node3""]}}" + ); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ИспользоватьПровайдерJSON(); + Менеджер.УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "Кластер"); + + // Act + Менеджер.Прочитать(); + Менеджер.ЗаполнитьОбъектПараметров(ДТО, "Кластер"); + + // Assert + Ожидаем.Что(ДТО.Имя, "Имя кластера должно быть из конфига").Равно("prod-cluster"); + Ожидаем.Что(ДТО.Узлы.Количество(), "Должно быть 3 узла").Равно(3); + Ожидаем.Что(ДТО.Узлы[0], "Первый узел").Равно("node1"); + Ожидаем.Что(ДТО.Узлы[1], "Второй узел").Равно("node2"); + Ожидаем.Что(ДТО.Узлы[2], "Третий узел").Равно("node3"); + + УдалитьФайлы(ВременныйФайл); + +КонецПроцедуры + Функция ПолучитьВременныйФайлJSON(Знач СодержимоеJSON) ВременныйФайл = ПолучитьИмяВременногоФайла("json"); From 955e00ce8db6ab9af6ecafcc5b7742043d0a0fad Mon Sep 17 00:00:00 2001 From: Egor Ivanov Date: Sat, 11 Apr 2026 02:21:30 +0300 Subject: [PATCH 05/13] =?UTF-8?q?=D0=92=D0=BB=D0=BE=D0=B6=D0=B5=D0=BD?= =?UTF-8?q?=D0=BD=D1=8B=D0=B5=20=D1=81=D1=85=D0=B5=D0=BC=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packagedef | 1 + ...20\275\320\275\321\213\320\271\320\224\320\242\320\236.os" | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packagedef b/packagedef index ca63b73..1d888ec 100644 --- a/packagedef +++ b/packagedef @@ -29,4 +29,5 @@ .ОпределяетКласс("КонструкторПараметров", "src/Классы/КонструкторПараметров.os") .ОпределяетКласс("АннотацияЗначениеПоУмолчанию", "src/Классы/АннотацияЗначениеПоУмолчанию.os") .ОпределяетКласс("АннотацияСиноним", "src/Классы/АннотацияСиноним.os") + .ОпределяетКласс("АннотацияВложенныйДТО", "src/Классы/АннотацияВложенныйДТО.os") ; diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\222\320\273\320\276\320\266\320\265\320\275\320\275\321\213\320\271\320\224\320\242\320\236.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\222\320\273\320\276\320\266\320\265\320\275\320\275\321\213\320\271\320\224\320\242\320\236.os" index c8b894f..628a16a 100644 --- "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\222\320\273\320\276\320\266\320\265\320\275\320\275\321\213\320\271\320\224\320\242\320\236.os" +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\222\320\273\320\276\320\266\320\265\320\275\320\275\321\213\320\271\320\224\320\242\320\236.os" @@ -19,6 +19,6 @@ КонецФункции &Аннотация("ВложенныйДТО") -Процедура ПриСозданииОбъекта(ИмяКласса) Экспорт - _ИмяКласса = ИмяКласса; +Процедура ПриСозданииОбъекта(Значение) Экспорт + _ИмяКласса = Значение; КонецПроцедуры From 32da5aa3440562408e8b9287db2eba563271e61d Mon Sep 17 00:00:00 2001 From: Egor Ivanov Date: Mon, 13 Apr 2026 13:54:54 +0300 Subject: [PATCH 06/13] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81=D1=8B=20=D0=BF?= =?UTF-8?q?=D0=BE=20=D0=BA=D0=BE=D0=BC=D0=BC=D0=B5=D0=BD=D1=82=D0=B0=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packagedef | 2 +- ...20\273\321\214\320\224\320\242\320\236.os" | 44 +++++-------------- ...21\213\320\271\320\224\320\242\320\236.os" | 14 +----- ...20\265\321\202\321\200\320\276\320\262.os" | 16 ++++--- ...20\260\320\275\320\275\321\213\321\205.os" | 1 + ...21\202\320\260\321\206\320\270\321\217.os" | 4 +- ...20\266\320\265\320\275\320\270\320\265.os" | 1 + 7 files changed, 27 insertions(+), 55 deletions(-) diff --git a/packagedef b/packagedef index 1d888ec..8cd5dda 100644 --- a/packagedef +++ b/packagedef @@ -19,7 +19,7 @@ .ЗависитОт("tempfiles") .ЗависитОт("1connector", "2.3.3") .ЗависитОт("reflector", "0.3.1") - .ЗависитОт("annotations") + .ЗависитОт("annotations", "1.3.1") .РазработкаЗависитОт("coverage", "0.6.1") .РазработкаЗависитОт("1testrunner", "1.9.2") .РазработкаЗависитОт("1bdd", "1.14.0") diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236.os" index 7b1543a..6372baa 100644 --- "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236.os" +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236.os" @@ -1,5 +1,6 @@ #Использовать annotations #Использовать reflector +#Использовать logos Перем КонтейнерАннотаций; Перем Лог; @@ -49,43 +50,20 @@ ИначеЕсли ИмяАннотации = "ВЛОЖЕННЫЙДТО" Тогда - ВложенныйОбъект = Новый(ОбъектАннотации.ИмяКласса()); - ВложенныеОписания = ОписатьКласс(ВложенныйОбъект); - ОписаниеПоля.УстановитьВложенныйОбъект(ВложенныйОбъект, ВложенныеОписания); - СтандартныйРефлектор = Новый Рефлектор; - СтандартныйРефлектор.УстановитьСвойство(КлассОбъект, Свойство.Имя, ВложенныйОбъект); + ВложенныйОбъект = СтандартныйРефлектор.ПолучитьСвойство(КлассОбъект, Свойство.Имя); + + Если ВложенныйОбъект <> Неопределено Тогда + ВложенныеОписания = ОписатьКласс(ВложенныйОбъект); + ОписаниеПоля.УстановитьВложенныйОбъект(ВложенныйОбъект, ВложенныеОписания); + Иначе + Лог.Предупреждение("Свойство <%1> помечено как вложенный DTO, но не инициализировано в конструкторе", Свойство.Имя); + КонецЕсли; КонецЕсли; КонецЦикла; - // Проверяем, является ли текущее значение свойства вложенным DTO-объектом - // (если аннотация &ВложенныйДТО не была задана явно) - Если Не ОписаниеПоля.ЭтоВложенныйДТО() Тогда - Попытка - СтандартныйРефлектор = Новый Рефлектор; - ЗначениеСвойства = СтандартныйРефлектор.ПолучитьСвойство(КлассОбъект, Свойство.Имя); - Если Не ЗначениеСвойства = Неопределено Тогда - ВложенныйРефлектор = Новый РефлекторОбъекта(ЗначениеСвойства); - ВложенныеСвойства = ВложенныйРефлектор.ПолучитьТаблицуСвойств(Неопределено, Истина); - ЕстьЭкспортныеСвойства = Ложь; - Для Каждого ВлСвойство Из ВложенныеСвойства Цикл - Если ВлСвойство.Экспорт Тогда - ЕстьЭкспортныеСвойства = Истина; - Прервать; - КонецЕсли; - КонецЦикла; - Если ЕстьЭкспортныеСвойства Тогда - ВложенныеОписания = ОписатьКласс(ЗначениеСвойства); - ОписаниеПоля.УстановитьВложенныйОбъект(ЗначениеСвойства, ВложенныеОписания); - КонецЕсли; - КонецЕсли; - Исключение - // Значение недоступно или не является объектом — пропускаем - КонецПопытки; - КонецЕсли; - ОписанияПолей.Добавить(ОписаниеПоля); КонецЦикла; @@ -101,6 +79,6 @@ КонтейнерАннотаций.ДобавитьАннотацию(Тип("АннотацияСиноним")); КонтейнерАннотаций.ДобавитьАннотацию(Тип("АннотацияВложенныйДТО")); -КонецПроцедуры + Лог = Логирование.ПолучитьЛог("oscript.lib.configor.dto"); -Лог = Логирование.ПолучитьЛог("oscript.lib.configor.dto"); +КонецПроцедуры diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\222\320\273\320\276\320\266\320\265\320\275\320\275\321\213\320\271\320\224\320\242\320\236.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\222\320\273\320\276\320\266\320\265\320\275\320\275\321\213\320\271\320\224\320\242\320\236.os" index 628a16a..54dcb7a 100644 --- "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\222\320\273\320\276\320\266\320\265\320\275\320\275\321\213\320\271\320\224\320\242\320\236.os" +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\222\320\273\320\276\320\266\320\265\320\275\320\275\321\213\320\271\320\224\320\242\320\236.os" @@ -1,5 +1,3 @@ -Перем _ИмяКласса; - // Возвращает имя аннотации // // Возвращаемое значение: @@ -9,16 +7,6 @@ Возврат "ВложенныйДТО"; КонецФункции -// Возвращает имя класса вложенного DTO -// -// Возвращаемое значение: -// Строка - имя класса -// -Функция ИмяКласса() Экспорт - Возврат _ИмяКласса; -КонецФункции - &Аннотация("ВложенныйДТО") -Процедура ПриСозданииОбъекта(Значение) Экспорт - _ИмяКласса = Значение; +Процедура ПриСозданииОбъекта() Экспорт КонецПроцедуры diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\276\320\262.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\276\320\262.os" index 450f7a2..6456baf 100644 --- "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\276\320\262.os" +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\276\320\262.os" @@ -319,15 +319,19 @@ // Процедура ЗарегистрироватьКлассПараметров(Знач КлассОбъект, Знач Префикс) Экспорт - Если ВнутреннийОписательДТО = Неопределено Тогда - ВнутреннийОписательДТО = Новый ОписательДТО; - КонецЕсли; - ОписанияПолей = ВнутреннийОписательДТО.ОписатьКласс(КлассОбъект); Лог.Отладка("Зарегистрирован класс параметров с префиксом <%1>, полей: %2", Префикс, ОписанияПолей.Количество()); - РеестрКлассовПараметров.Вставить(Префикс, ОписанияПолей); + СуществующиеОписания = РеестрКлассовПараметров[Префикс]; + + Если СуществующиеОписания <> Неопределено Тогда + Для Каждого Описание Из ОписанияПолей Цикл + СуществующиеОписания.Добавить(Описание); + КонецЦикла; + Иначе + РеестрКлассовПараметров.Вставить(Префикс, ОписанияПолей); + КонецЕсли; КонецПроцедуры @@ -597,7 +601,7 @@ ВнутреннийКонструкторПараметров = Неопределено; ИспользуетсяКонструкторПараметров = Ложь; - ВнутреннийОписательДТО = Неопределено; + ВнутреннийОписательДТО = Новый ОписательДТО; РеестрКлассовПараметров = Новый Соответствие; КонецПроцедуры diff --git "a/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\221\320\260\320\267\320\260\320\224\320\260\320\275\320\275\321\213\321\205.os" "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\221\320\260\320\267\320\260\320\224\320\260\320\275\320\275\321\213\321\205.os" index f4292f6..32a3650 100644 --- "a/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\221\320\260\320\267\320\260\320\224\320\260\320\275\320\275\321\213\321\205.os" +++ "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\221\320\260\320\267\320\260\320\224\320\260\320\275\320\275\321\213\321\205.os" @@ -3,6 +3,7 @@ &ЗначениеПоУмолчанию("main_db") Перем ИмяБазы Экспорт; +&ВложенныйДТО Перем Подключение Экспорт; Процедура ПриСозданииОбъекта() diff --git "a/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\221\320\260\320\267\320\260\320\224\320\260\320\275\320\275\321\213\321\205\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217.os" "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\221\320\260\320\267\320\260\320\224\320\260\320\275\320\275\321\213\321\205\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217.os" index 2c8f717..6d7108b 100644 --- "a/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\221\320\260\320\267\320\260\320\224\320\260\320\275\320\275\321\213\321\205\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217.os" +++ "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\221\320\260\320\267\320\260\320\224\320\260\320\275\320\275\321\213\321\205\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217.os" @@ -4,9 +4,9 @@ &ЗначениеПоУмолчанию("main_db") Перем ИмяБазы Экспорт; -&ВложенныйДТО("ТестовоеПодключение") +&ВложенныйДТО Перем Подключение Экспорт; Процедура ПриСозданииОбъекта() - + Подключение = ЗагрузитьСценарий(ОбъединитьПути(ТекущийСценарий().Каталог, "ТестовоеПодключение.os")); КонецПроцедуры diff --git "a/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\320\265.os" "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\320\265.os" index b66341e..40ceb7d 100644 --- "a/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\320\265.os" +++ "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\320\265.os" @@ -6,6 +6,7 @@ &ЗначениеПоУмолчанию("1.0.0") Перем Версия Экспорт; +&ВложенныйДТО Перем БазаДанных Экспорт; Процедура ПриСозданииОбъекта() From 9c1257d52643e11159cfa90369dc258c9935552e Mon Sep 17 00:00:00 2001 From: Egor Ivanov Date: Mon, 13 Apr 2026 13:55:24 +0300 Subject: [PATCH 07/13] bump annotations version --- packagedef | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packagedef b/packagedef index 8cd5dda..89759cc 100644 --- a/packagedef +++ b/packagedef @@ -19,7 +19,7 @@ .ЗависитОт("tempfiles") .ЗависитОт("1connector", "2.3.3") .ЗависитОт("reflector", "0.3.1") - .ЗависитОт("annotations", "1.3.1") + .ЗависитОт("annotations", "1.4.0") .РазработкаЗависитОт("coverage", "0.6.1") .РазработкаЗависитОт("1testrunner", "1.9.2") .РазработкаЗависитОт("1bdd", "1.14.0") From 9be5cffe3220cf327685d67e705e3a64b6e703ee Mon Sep 17 00:00:00 2001 From: Egor Ivanov Date: Mon, 13 Apr 2026 14:42:57 +0300 Subject: [PATCH 08/13] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20=D0=BA=D0=B0=D1=81=D1=82=20=D1=82=D0=B8=D0=BF?= =?UTF-8?q?=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packagedef | 1 + ...20\273\321\217\320\224\320\242\320\236.os" | 11 +- ...20\273\321\214\320\224\320\242\320\236.os" | 5 + ...20\274\320\265\321\202\321\200\320\260.os" | 24 ++++ ...20\265\321\202\321\200\320\276\320\262.os" | 51 +++++++ ...20\270\320\277\320\260\320\274\320\270.os" | 13 ++ ...20\270\320\277\320\260\320\274\320\270.os" | 11 ++ ...20\270\320\277\320\260\320\274\320\270.os" | 16 +++ ...3\321\214\320\224\320\242\320\236_test.os" | 132 ++++++++++++++++++ 9 files changed, 261 insertions(+), 3 deletions(-) create mode 100644 "src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\242\320\270\320\277\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\260.os" create mode 100644 "tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\320\276\320\265\320\237\320\276\320\264\320\272\320\273\321\216\321\207\320\265\320\275\320\270\320\265\320\241\320\242\320\270\320\277\320\260\320\274\320\270.os" create mode 100644 "tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\221\320\260\320\267\320\260\320\224\320\260\320\275\320\275\321\213\321\205\320\241\320\242\320\270\320\277\320\260\320\274\320\270.os" create mode 100644 "tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\241\320\242\320\270\320\277\320\260\320\274\320\270.os" diff --git a/packagedef b/packagedef index 89759cc..deea22b 100644 --- a/packagedef +++ b/packagedef @@ -29,5 +29,6 @@ .ОпределяетКласс("КонструкторПараметров", "src/Классы/КонструкторПараметров.os") .ОпределяетКласс("АннотацияЗначениеПоУмолчанию", "src/Классы/АннотацияЗначениеПоУмолчанию.os") .ОпределяетКласс("АннотацияСиноним", "src/Классы/АннотацияСиноним.os") + .ОпределяетКласс("АннотацияТипПараметра", "src/Классы/АннотацияТипПараметра.os") .ОпределяетКласс("АннотацияВложенныйДТО", "src/Классы/АннотацияВложенныйДТО.os") ; diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265\320\237\320\276\320\273\321\217\320\224\320\242\320\236.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265\320\237\320\276\320\273\321\217\320\224\320\242\320\236.os" index 313d4d7..cdeb01e 100644 --- "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265\320\237\320\276\320\273\321\217\320\224\320\242\320\236.os" +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265\320\237\320\276\320\273\321\217\320\224\320\242\320\236.os" @@ -35,10 +35,15 @@ ЗначениеПоУмолчанию = Значение; Обязательное = Ложь; - Если Не Значение = Неопределено Тогда - Тип = ТипЗнч(Значение); - КонецЕсли; +КонецПроцедуры +// Устанавливает тип значения явно (из аннотации &Тип) +// +// Параметры: +// НовыйТип - Тип - целевой тип значения +// +Процедура УстановитьТип(Знач НовыйТип) Экспорт + Тип = НовыйТип; КонецПроцедуры // Устанавливает синоним поля diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236.os" index 6372baa..eb7fe64 100644 --- "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236.os" +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236.os" @@ -48,6 +48,10 @@ ОписаниеПоля.УстановитьСиноним(ОбъектАннотации.Синоним()); + ИначеЕсли ИмяАннотации = "ТИП" Тогда + + ОписаниеПоля.УстановитьТип(ОбъектАннотации.ТипЗначения()); + ИначеЕсли ИмяАннотации = "ВЛОЖЕННЫЙДТО" Тогда СтандартныйРефлектор = Новый Рефлектор; @@ -77,6 +81,7 @@ КонтейнерАннотаций = Новый КонтейнерАннотаций; КонтейнерАннотаций.ДобавитьАннотацию(Тип("АннотацияЗначениеПоУмолчанию")); КонтейнерАннотаций.ДобавитьАннотацию(Тип("АннотацияСиноним")); + КонтейнерАннотаций.ДобавитьАннотацию(Тип("АннотацияТипПараметра")); КонтейнерАннотаций.ДобавитьАннотацию(Тип("АннотацияВложенныйДТО")); Лог = Логирование.ПолучитьЛог("oscript.lib.configor.dto"); diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\242\320\270\320\277\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\260.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\242\320\270\320\277\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\260.os" new file mode 100644 index 0000000..b220e65 --- /dev/null +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\242\320\270\320\277\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\260.os" @@ -0,0 +1,24 @@ +Перем _Тип; + +// Возвращает имя аннотации +// +// Возвращаемое значение: +// Строка - имя аннотации +// +Функция ИмяАннотации() Экспорт + Возврат "Тип"; +КонецФункции + +// Возвращает тип значения +// +// Возвращаемое значение: +// Тип - целевой тип значения +// +Функция ТипЗначения() Экспорт + Возврат _Тип; +КонецФункции + +&Аннотация("Тип") +Процедура ПриСозданииОбъекта(Значение) Экспорт + _Тип = Тип(Значение); +КонецПроцедуры diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\276\320\262.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\276\320\262.os" index 6456baf..f6905c5 100644 --- "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\276\320\262.os" +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\276\320\262.os" @@ -368,6 +368,7 @@ Если Не ЗначениеИзКонфига = Неопределено Тогда + ЗначениеИзКонфига = ПривестиЗначениеКТипу(ЗначениеИзКонфига, ОписаниеПоля); Лог.Отладка("Установка свойства <%1> из параметра <%2>", ОписаниеПоля.Имя, ПолныйКлюч); ОбъектРефлектор.УстановитьСвойство(КлассОбъект, ОписаниеПоля.Имя, ЗначениеИзКонфига); @@ -414,6 +415,7 @@ Если Не ЗначениеИзКонфига = Неопределено Тогда + ЗначениеИзКонфига = ПривестиЗначениеКТипу(ЗначениеИзКонфига, ВложенноеОписание); Лог.Отладка("Установка вложенного свойства <%1> из параметра <%2>", ВложенноеОписание.Имя, ПолныйКлюч); ОбъектРефлектор.УстановитьСвойство(ВложенныйОбъект, ВложенноеОписание.Имя, ЗначениеИзКонфига); @@ -442,6 +444,55 @@ КонецФункции +Функция ПривестиЗначениеКТипу(Знач Значение, Знач ОписаниеПоля) + + ЦелевойТип = ОписаниеПоля.Тип; + + Если ЦелевойТип = Неопределено Тогда + Возврат Значение; + КонецЕсли; + + Если ТипЗнч(Значение) = ЦелевойТип Тогда + Возврат Значение; + КонецЕсли; + + Попытка + + Если ЦелевойТип = Тип("Дата") Тогда + // ОписаниеТипов не парсит ISO-формат + Возврат XMLЗначение(Тип("Дата"), Значение); + Иначе + + // Для булево: "1"/"0" не поддерживаются ОписаниеТипов — подменяем + Если ЦелевойТип = Тип("Булево") И ТипЗнч(Значение) = Тип("Строка") Тогда + СтрЗначение = СокрЛП(Значение); + Если СтрЗначение = "1" Тогда + Возврат Истина; + ИначеЕсли СтрЗначение = "0" Тогда + Возврат Ложь; + КонецЕсли; + КонецЕсли; + + ОписаниеТипов = Новый ОписаниеТипов(Строка(ЦелевойТип)); + Результат = ОписаниеТипов.ПривестиЗначение(Значение); + + // ОписаниеТипов.ПривестиЗначение не бросает ошибку для невалидных строк + Если ЦелевойТип = Тип("Число") И ТипЗнч(Значение) = Тип("Строка") Тогда + Если Результат = 0 И СокрЛП(Значение) <> "0" Тогда + ВызватьИсключение "Невалидное числовое значение"; + КонецЕсли; + КонецЕсли; + + Возврат Результат; + КонецЕсли; + + Исключение + ВызватьИсключение "Не удалось привести значение параметра """ + + ОписаниеПоля.Имя + """ (" + Значение + ") к типу " + ЦелевойТип; + КонецПопытки; + +КонецФункции + Процедура ВыполнитьЧтениеПровайдеров() КоллекцияПровайдеров = Новый ПроцессорКоллекций; diff --git "a/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\320\276\320\265\320\237\320\276\320\264\320\272\320\273\321\216\321\207\320\265\320\275\320\270\320\265\320\241\320\242\320\270\320\277\320\260\320\274\320\270.os" "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\320\276\320\265\320\237\320\276\320\264\320\272\320\273\321\216\321\207\320\265\320\275\320\270\320\265\320\241\320\242\320\270\320\277\320\260\320\274\320\270.os" new file mode 100644 index 0000000..1c79b01 --- /dev/null +++ "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\320\276\320\265\320\237\320\276\320\264\320\272\320\273\321\216\321\207\320\265\320\275\320\270\320\265\320\241\320\242\320\270\320\277\320\260\320\274\320\270.os" @@ -0,0 +1,13 @@ +// Вложенный DTO с аннотациями типов + +&Тип("Строка") +Перем Хост Экспорт; + +&Тип("Число") +Перем Порт Экспорт; + +&Тип("Булево") +Перем SSL Экспорт; + +Процедура ПриСозданииОбъекта() +КонецПроцедуры diff --git "a/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\221\320\260\320\267\320\260\320\224\320\260\320\275\320\275\321\213\321\205\320\241\320\242\320\270\320\277\320\260\320\274\320\270.os" "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\221\320\260\320\267\320\260\320\224\320\260\320\275\320\275\321\213\321\205\320\241\320\242\320\270\320\277\320\260\320\274\320\270.os" new file mode 100644 index 0000000..4c5bccd --- /dev/null +++ "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\221\320\260\320\267\320\260\320\224\320\260\320\275\320\275\321\213\321\205\320\241\320\242\320\270\320\277\320\260\320\274\320\270.os" @@ -0,0 +1,11 @@ +// DTO с вложенным DTO, оба используют аннотации типов + +&Тип("Строка") +Перем ИмяБазы Экспорт; + +&ВложенныйДТО +Перем Подключение Экспорт; + +Процедура ПриСозданииОбъекта() + Подключение = ЗагрузитьСценарий(ОбъединитьПути(ТекущийСценарий().Каталог, "ТестовоеПодключениеСТипами.os")); +КонецПроцедуры diff --git "a/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\241\320\242\320\270\320\277\320\260\320\274\320\270.os" "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\241\320\242\320\270\320\277\320\260\320\274\320\270.os" new file mode 100644 index 0000000..083a9d7 --- /dev/null +++ "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\241\320\242\320\270\320\277\320\260\320\274\320\270.os" @@ -0,0 +1,16 @@ +// DTO с аннотациями типов для проверки приведения типов + +&Тип("Число") +Перем Порт Экспорт; + +&Тип("Булево") +Перем Включен Экспорт; + +&Тип("Строка") +Перем Название Экспорт; + +&Тип("Дата") +Перем ДатаЗапуска Экспорт; + +Процедура ПриСозданииОбъекта() +КонецПроцедуры diff --git "a/tests/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236_test.os" "b/tests/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236_test.os" index 48105e0..fe4c9f6 100644 --- "a/tests/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236_test.os" +++ "b/tests/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236_test.os" @@ -24,6 +24,11 @@ ИменаТестов.Добавить("ТестДолжен_ЗаполнитьДвухуровневыйДТО"); ИменаТестов.Добавить("ТестДолжен_ПрименитьУмолчанияВоВложенномДТО"); ИменаТестов.Добавить("ТестДолжен_ОбработатьМассивВоВложенномДТО"); + ИменаТестов.Добавить("ТестДолжен_ПривестиСтрокуКЧислуПоАннотацииТип"); + ИменаТестов.Добавить("ТестДолжен_ПривестиСтрокуКБулевоПоАннотацииТип"); + ИменаТестов.Добавить("ТестДолжен_ВыброситьИсключениеПриНевозможностиПриведенияТипа"); + ИменаТестов.Добавить("ТестДолжен_ПривестиТипыВоВложенномДТО"); + ИменаТестов.Добавить("ТестДолжен_НеПриводитьЕслиТипСовпадает"); Возврат ИменаТестов; @@ -311,6 +316,133 @@ КонецПроцедуры +// КП-3.1: Приведение строки к числу по &Тип("Число") +Процедура ТестДолжен_ПривестиСтрокуКЧислуПоАннотацииТип() Экспорт + + ДТО = ЗагрузитьДТО("ТестовыйДТОСТипами.os"); + + // Имитируем ситуацию, когда из ENV/INI приходят строки + ВременныйФайл = ПолучитьВременныйФайлJSON( + "{""cfg"": {""Порт"": ""8080"", ""Включен"": ""true"", ""Название"": 42, ""ДатаЗапуска"": ""2025-01-15T00:00:00""}}" + ); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ИспользоватьПровайдерJSON(); + Менеджер.УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "cfg"); + Менеджер.Прочитать(); + Менеджер.ЗаполнитьОбъектПараметров(ДТО, "cfg"); + + Ожидаем.Что(ТипЗнч(ДТО.Порт), "Порт должен быть числом").Равно(Тип("Число")); + Ожидаем.Что(ДТО.Порт, "Порт должен быть 8080").Равно(8080); + + УдалитьФайлы(ВременныйФайл); + +КонецПроцедуры + +// КП-3.2: Приведение строки к булево по &Тип("Булево") +Процедура ТестДолжен_ПривестиСтрокуКБулевоПоАннотацииТип() Экспорт + + ДТО = ЗагрузитьДТО("ТестовыйДТОСТипами.os"); + + ВременныйФайл = ПолучитьВременныйФайлJSON( + "{""cfg"": {""Порт"": ""3306"", ""Включен"": ""Истина"", ""Название"": ""test"", ""ДатаЗапуска"": ""2025-06-01T00:00:00""}}" + ); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ИспользоватьПровайдерJSON(); + Менеджер.УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "cfg"); + Менеджер.Прочитать(); + Менеджер.ЗаполнитьОбъектПараметров(ДТО, "cfg"); + + Ожидаем.Что(ТипЗнч(ДТО.Включен), "Включен должен быть булево").Равно(Тип("Булево")); + Ожидаем.Что(ДТО.Включен, "Включен должен быть Истина").Равно(Истина); + + УдалитьФайлы(ВременныйФайл); + +КонецПроцедуры + +// КП-3.3: Ошибка при невозможности приведения типа +Процедура ТестДолжен_ВыброситьИсключениеПриНевозможностиПриведенияТипа() Экспорт + + ДТО = ЗагрузитьДТО("ТестовыйДТОСТипами.os"); + + ВременныйФайл = ПолучитьВременныйФайлJSON( + "{""cfg"": {""Порт"": ""not_a_number"", ""Включен"": ""false"", ""Название"": ""test"", ""ДатаЗапуска"": ""2025-01-01T00:00:00""}}" + ); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ИспользоватьПровайдерJSON(); + Менеджер.УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "cfg"); + Менеджер.Прочитать(); + + Попытка + Менеджер.ЗаполнитьОбъектПараметров(ДТО, "cfg"); + Ожидаем.Что(Ложь, "Ожидалось исключение приведения типа").Равно(Истина); + Исключение + Ожидаем.Что(ОписаниеОшибки()).Содержит("Порт"); + КонецПопытки; + + УдалитьФайлы(ВременныйФайл); + +КонецПроцедуры + +// КП-3.4: Приведение типов во вложенном ДТО +Процедура ТестДолжен_ПривестиТипыВоВложенномДТО() Экспорт + + ДТО = ЗагрузитьДТО("ТестовыйДТОБазаДанныхСТипами.os"); + + // Все значения как строки (имитация ENV) + ВременныйФайл = ПолучитьВременныйФайлJSON( + "{""db"": {""ИмяБазы"": ""test_db"", ""Подключение"": {""Хост"": ""db-host"", ""Порт"": ""5432"", ""SSL"": ""true""}}}" + ); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ИспользоватьПровайдерJSON(); + Менеджер.УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "db"); + Менеджер.Прочитать(); + Менеджер.ЗаполнитьОбъектПараметров(ДТО, "db"); + + Ожидаем.Что(ТипЗнч(ДТО.ИмяБазы), "ИмяБазы должно быть строкой").Равно(Тип("Строка")); + Ожидаем.Что(ДТО.Подключение.Хост, "Вложенный Хост должен быть строкой").Равно("db-host"); + Ожидаем.Что(ТипЗнч(ДТО.Подключение.Порт), "Вложенный Порт должен стать числом").Равно(Тип("Число")); + Ожидаем.Что(ДТО.Подключение.Порт, "Вложенный Порт должен быть 5432").Равно(5432); + Ожидаем.Что(ТипЗнч(ДТО.Подключение.SSL), "Вложенный SSL должен стать булево").Равно(Тип("Булево")); + Ожидаем.Что(ДТО.Подключение.SSL, "Вложенный SSL должен быть Истина").Равно(Истина); + + УдалитьФайлы(ВременныйФайл); + +КонецПроцедуры + +// КП-3.5: Не приводить если тип уже совпадает +Процедура ТестДолжен_НеПриводитьЕслиТипСовпадает() Экспорт + + ДТО = ЗагрузитьДТО("ТестовыйДТОСТипами.os"); + + // JSON провайдер вернёт число как число — приведение не нужно + ВременныйФайл = ПолучитьВременныйФайлJSON( + "{""cfg"": {""Порт"": 8080, ""Включен"": true, ""Название"": ""test"", ""ДатаЗапуска"": ""2025-01-01T00:00:00""}}" + ); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ИспользоватьПровайдерJSON(); + Менеджер.УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "cfg"); + Менеджер.Прочитать(); + Менеджер.ЗаполнитьОбъектПараметров(ДТО, "cfg"); + + Ожидаем.Что(ТипЗнч(ДТО.Порт), "Порт должен остаться числом").Равно(Тип("Число")); + Ожидаем.Что(ДТО.Порт, "Порт должен быть 8080").Равно(8080); + Ожидаем.Что(ТипЗнч(ДТО.Включен), "Включен должен остаться булево").Равно(Тип("Булево")); + Ожидаем.Что(ДТО.Включен, "Включен должен быть true").Равно(Истина); + + УдалитьФайлы(ВременныйФайл); + +КонецПроцедуры + Функция ПолучитьВременныйФайлJSON(Знач СодержимоеJSON) ВременныйФайл = ПолучитьИмяВременногоФайла("json"); From 977bbcec7b942d22f76a46489a8f2b9f3c3ee62f Mon Sep 17 00:00:00 2001 From: Egor Ivanov Date: Mon, 13 Apr 2026 15:01:43 +0300 Subject: [PATCH 09/13] =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B5=D0=BF=D0=B8?= =?UTF-8?q?=D1=81=D0=B0=D0=BB=20=D1=85=D1=80=D0=B0=D0=BD=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5=20=D1=80=D0=B5=D0=B5=D1=81=D1=82=D1=80=D0=B0=20=D0=BA?= =?UTF-8?q?=D0=BB=D0=B0=D1=81=D1=81=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...20\265\321\202\321\200\320\276\320\262.os" | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\276\320\262.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\276\320\262.os" index f6905c5..14eba9e 100644 --- "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\276\320\262.os" +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\276\320\262.os" @@ -23,7 +23,7 @@ Перем ИспользуетсяКонструкторПараметров; // булево Перем ВнутреннийОписательДТО; // Класс ОписательДТО -Перем РеестрКлассовПараметров; // Соответствие: Префикс -> ОписанияПолей (Массив ОписаниеПоляДТО) +Перем РеестрКлассовПараметров; // Соответствие: КлассОбъект -> Структура(Префикс, ОписанияПолей) Перем Лог; // Логгер @@ -323,15 +323,8 @@ Лог.Отладка("Зарегистрирован класс параметров с префиксом <%1>, полей: %2", Префикс, ОписанияПолей.Количество()); - СуществующиеОписания = РеестрКлассовПараметров[Префикс]; - - Если СуществующиеОписания <> Неопределено Тогда - Для Каждого Описание Из ОписанияПолей Цикл - СуществующиеОписания.Добавить(Описание); - КонецЦикла; - Иначе - РеестрКлассовПараметров.Вставить(Префикс, ОписанияПолей); - КонецЕсли; + Запись = Новый Структура("Префикс, ОписанияПолей", Префикс, ОписанияПолей); + РеестрКлассовПараметров.Вставить(КлассОбъект, Запись); КонецПроцедуры @@ -344,12 +337,14 @@ // Процедура ЗаполнитьОбъектПараметров(Знач КлассОбъект, Знач Префикс) Экспорт - ОписанияПолей = РеестрКлассовПараметров[Префикс]; + Запись = РеестрКлассовПараметров[КлассОбъект]; - Если ОписанияПолей = Неопределено Тогда + Если Запись = Неопределено Тогда ВызватьИсключение "Класс параметров с префиксом """ + Префикс + """ не зарегистрирован"; КонецЕсли; + ОписанияПолей = Запись.ОписанияПолей; + ОбъектРефлектор = Новый Рефлектор; Для Каждого ОписаниеПоля Из ОписанияПолей Цикл From 37f6f9ba6da3f5e1e6a3f4e4c9b4411ae63edcaa Mon Sep 17 00:00:00 2001 From: Egor Ivanov Date: Mon, 13 Apr 2026 15:34:30 +0300 Subject: [PATCH 10/13] =?UTF-8?q?=D0=A3=D0=B1=D1=80=D0=B0=D0=BB=20=D0=BE?= =?UTF-8?q?=D0=BF=D1=80=D0=B5=D0=B4=D0=B5=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20?= =?UTF-8?q?=D0=B0=D0=BD=D0=BD=D0=BE=D1=82=D0=B0=D1=86=D0=B8=D0=B8=20=D0=B8?= =?UTF-8?q?=20=D0=BF=D0=BE=D0=BB=D1=83=D1=87=D0=B0=D1=8E=20=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D1=81=D1=82=D0=BE=20=D0=BF=D0=BE=20=D0=B8=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packagedef | 1 - ...20\273\321\214\320\224\320\242\320\236.os" | 11 +++++---- ...20\274\320\265\321\202\321\200\320\260.os" | 24 ------------------- 3 files changed, 6 insertions(+), 30 deletions(-) delete mode 100644 "src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\242\320\270\320\277\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\260.os" diff --git a/packagedef b/packagedef index deea22b..89759cc 100644 --- a/packagedef +++ b/packagedef @@ -29,6 +29,5 @@ .ОпределяетКласс("КонструкторПараметров", "src/Классы/КонструкторПараметров.os") .ОпределяетКласс("АннотацияЗначениеПоУмолчанию", "src/Классы/АннотацияЗначениеПоУмолчанию.os") .ОпределяетКласс("АннотацияСиноним", "src/Классы/АннотацияСиноним.os") - .ОпределяетКласс("АннотацияТипПараметра", "src/Классы/АннотацияТипПараметра.os") .ОпределяетКласс("АннотацияВложенныйДТО", "src/Классы/АннотацияВложенныйДТО.os") ; diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236.os" index eb7fe64..8a3d5ef 100644 --- "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236.os" +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236.os" @@ -32,6 +32,12 @@ ИмяАннотации = Врег(Аннотация.Имя); + Если ИмяАннотации = "ТИП" Тогда + ЗначениеТипа = РаботаСАннотациями.ПолучитьЗначениеПараметраАннотации(Аннотация); + ОписаниеПоля.УстановитьТип(Тип(ЗначениеТипа)); + Продолжить; + КонецЕсли; + ОпределениеАннотации = КонтейнерАннотаций.ПолучитьОпределениеАннотации(Аннотация.Имя); Если ОпределениеАннотации = Неопределено Тогда @@ -48,10 +54,6 @@ ОписаниеПоля.УстановитьСиноним(ОбъектАннотации.Синоним()); - ИначеЕсли ИмяАннотации = "ТИП" Тогда - - ОписаниеПоля.УстановитьТип(ОбъектАннотации.ТипЗначения()); - ИначеЕсли ИмяАннотации = "ВЛОЖЕННЫЙДТО" Тогда СтандартныйРефлектор = Новый Рефлектор; @@ -81,7 +83,6 @@ КонтейнерАннотаций = Новый КонтейнерАннотаций; КонтейнерАннотаций.ДобавитьАннотацию(Тип("АннотацияЗначениеПоУмолчанию")); КонтейнерАннотаций.ДобавитьАннотацию(Тип("АннотацияСиноним")); - КонтейнерАннотаций.ДобавитьАннотацию(Тип("АннотацияТипПараметра")); КонтейнерАннотаций.ДобавитьАннотацию(Тип("АннотацияВложенныйДТО")); Лог = Логирование.ПолучитьЛог("oscript.lib.configor.dto"); diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\242\320\270\320\277\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\260.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\242\320\270\320\277\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\260.os" deleted file mode 100644 index b220e65..0000000 --- "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\242\320\270\320\277\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\260.os" +++ /dev/null @@ -1,24 +0,0 @@ -Перем _Тип; - -// Возвращает имя аннотации -// -// Возвращаемое значение: -// Строка - имя аннотации -// -Функция ИмяАннотации() Экспорт - Возврат "Тип"; -КонецФункции - -// Возвращает тип значения -// -// Возвращаемое значение: -// Тип - целевой тип значения -// -Функция ТипЗначения() Экспорт - Возврат _Тип; -КонецФункции - -&Аннотация("Тип") -Процедура ПриСозданииОбъекта(Значение) Экспорт - _Тип = Тип(Значение); -КонецПроцедуры From c5dd1418071284e136024b69b2dc74efc33d2cfd Mon Sep 17 00:00:00 2001 From: Egor Ivanov Date: Mon, 13 Apr 2026 15:51:59 +0300 Subject: [PATCH 11/13] fix --- ...\320\275\320\275\321\213\320\271\320\224\320\242\320\236.os" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\222\320\273\320\276\320\266\320\265\320\275\320\275\321\213\320\271\320\224\320\242\320\236.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\222\320\273\320\276\320\266\320\265\320\275\320\275\321\213\320\271\320\224\320\242\320\236.os" index 54dcb7a..be38540 100644 --- "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\222\320\273\320\276\320\266\320\265\320\275\320\275\321\213\320\271\320\224\320\242\320\236.os" +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\222\320\273\320\276\320\266\320\265\320\275\320\275\321\213\320\271\320\224\320\242\320\236.os" @@ -8,5 +8,5 @@ КонецФункции &Аннотация("ВложенныйДТО") -Процедура ПриСозданииОбъекта() Экспорт +Процедура ПриСозданииОбъекта(Значение = "") Экспорт КонецПроцедуры From 25464ad18b7a5d558595405d64b5ee0f306da3d7 Mon Sep 17 00:00:00 2001 From: Egor Ivanov Date: Mon, 13 Apr 2026 16:04:35 +0300 Subject: [PATCH 12/13] =?UTF-8?q?=D0=98=D0=BD=D0=B8=D1=86=D0=B8=D0=B0?= =?UTF-8?q?=D0=BB=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D1=8F=20=D0=B2=D0=BB=D0=BE?= =?UTF-8?q?=D0=B6=D0=B5=D0=BD=D0=BD=D1=8B=D1=85=20=D0=B4=D1=82=D0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...0\265\320\273\321\214\320\224\320\242\320\236.os" | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236.os" index 8a3d5ef..cafa1cf 100644 --- "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236.os" +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236.os" @@ -59,11 +59,19 @@ СтандартныйРефлектор = Новый Рефлектор; ВложенныйОбъект = СтандартныйРефлектор.ПолучитьСвойство(КлассОбъект, Свойство.Имя); + Если ВложенныйОбъект = Неопределено Тогда + ИмяКлассаДТО = РаботаСАннотациями.ПолучитьЗначениеПараметраАннотации(Аннотация, , ""); + Если ИмяКлассаДТО <> "" Тогда + ВложенныйОбъект = Новый(ИмяКлассаДТО); + СтандартныйРефлектор.УстановитьСвойство(КлассОбъект, Свойство.Имя, ВложенныйОбъект); + Иначе + Лог.Предупреждение("Свойство <%1> помечено как вложенный DTO, но не инициализировано в конструкторе", Свойство.Имя); + КонецЕсли; + КонецЕсли; + Если ВложенныйОбъект <> Неопределено Тогда ВложенныеОписания = ОписатьКласс(ВложенныйОбъект); ОписаниеПоля.УстановитьВложенныйОбъект(ВложенныйОбъект, ВложенныеОписания); - Иначе - Лог.Предупреждение("Свойство <%1> помечено как вложенный DTO, но не инициализировано в конструкторе", Свойство.Имя); КонецЕсли; КонецЕсли; From 3f0df21878051d1bbfc97d9bb1941a7e9e8f6bad Mon Sep 17 00:00:00 2001 From: Egor Ivanov Date: Mon, 8 Jun 2026 15:02:29 +0300 Subject: [PATCH 13/13] =?UTF-8?q?=20=D1=84=D0=B8=D0=BA=D1=81=20=D0=BF?= =?UTF-8?q?=D0=BE=D1=81=D0=BB=D0=B5=20=D1=80=D0=B5=D0=B1=D0=B5=D0=B9=D0=B7?= =?UTF-8?q?=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packagedef | 2 +- ...3\321\214\320\224\320\242\320\236_test.os" | 80 +++++++++++-------- 2 files changed, 49 insertions(+), 33 deletions(-) diff --git a/packagedef b/packagedef index 89759cc..836c7b7 100644 --- a/packagedef +++ b/packagedef @@ -19,7 +19,7 @@ .ЗависитОт("tempfiles") .ЗависитОт("1connector", "2.3.3") .ЗависитОт("reflector", "0.3.1") - .ЗависитОт("annotations", "1.4.0") + .ЗависитОт("annotations", "1.3.0") .РазработкаЗависитОт("coverage", "0.6.1") .РазработкаЗависитОт("1testrunner", "1.9.2") .РазработкаЗависитОт("1bdd", "1.14.0") diff --git "a/tests/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236_test.os" "b/tests/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236_test.os" index fe4c9f6..0aba529 100644 --- "a/tests/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236_test.os" +++ "b/tests/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236_test.os" @@ -46,8 +46,9 @@ ВременныйФайл = ПолучитьВременныйФайлJSON("{""Тест"": {}}"); Менеджер = Новый МенеджерПараметров; - Менеджер.ИспользоватьПровайдерJSON(); - Менеджер.УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "Тест"); // Act @@ -70,8 +71,9 @@ ВременныйФайл = ПолучитьВременныйФайлJSON("{""Тест"": {""АдресСервера"": ""test""}}"); Менеджер = Новый МенеджерПараметров; - Менеджер.ИспользоватьПровайдерJSON(); - Менеджер.УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "Тест"); Менеджер.Прочитать(); @@ -95,8 +97,9 @@ ВременныйФайл = ПолучитьВременныйФайлJSON("{""Тест"": {""port"": 3306}}"); Менеджер = Новый МенеджерПараметров; - Менеджер.ИспользоватьПровайдерJSON(); - Менеджер.УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "Тест"); // Act @@ -120,8 +123,9 @@ ); Менеджер = Новый МенеджерПараметров; - Менеджер.ИспользоватьПровайдерJSON(); - Менеджер.УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "Префикс"); Менеджер.Прочитать(); Менеджер.ЗаполнитьОбъектПараметров(ДТО, "Префикс"); @@ -143,8 +147,9 @@ ); Менеджер = Новый МенеджерПараметров; - Менеджер.ИспользоватьПровайдерJSON(); - Менеджер.УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "Префикс"); Менеджер.Прочитать(); Менеджер.ЗаполнитьОбъектПараметров(ДТО, "Префикс"); @@ -166,8 +171,9 @@ ); Менеджер = Новый МенеджерПараметров; - Менеджер.ИспользоватьПровайдерJSON(); - Менеджер.УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "Префикс"); Менеджер.Прочитать(); @@ -192,8 +198,9 @@ ); Менеджер = Новый МенеджерПараметров; - Менеджер.ИспользоватьПровайдерJSON(); - Менеджер.УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "Префикс"); Менеджер.Прочитать(); Менеджер.ЗаполнитьОбъектПараметров(ДТО, "Префикс"); @@ -214,8 +221,9 @@ ); Менеджер = Новый МенеджерПараметров; - Менеджер.ИспользоватьПровайдерJSON(); - Менеджер.УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "БД"); // Act @@ -241,8 +249,9 @@ ); Менеджер = Новый МенеджерПараметров; - Менеджер.ИспользоватьПровайдерJSON(); - Менеджер.УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "Приложение"); // Act @@ -270,8 +279,9 @@ ); Менеджер = Новый МенеджерПараметров; - Менеджер.ИспользоватьПровайдерJSON(); - Менеджер.УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "БД"); // Act @@ -297,8 +307,9 @@ ); Менеджер = Новый МенеджерПараметров; - Менеджер.ИспользоватьПровайдерJSON(); - Менеджер.УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "Кластер"); // Act @@ -327,8 +338,9 @@ ); Менеджер = Новый МенеджерПараметров; - Менеджер.ИспользоватьПровайдерJSON(); - Менеджер.УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "cfg"); Менеджер.Прочитать(); Менеджер.ЗаполнитьОбъектПараметров(ДТО, "cfg"); @@ -350,8 +362,9 @@ ); Менеджер = Новый МенеджерПараметров; - Менеджер.ИспользоватьПровайдерJSON(); - Менеджер.УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "cfg"); Менеджер.Прочитать(); Менеджер.ЗаполнитьОбъектПараметров(ДТО, "cfg"); @@ -373,8 +386,9 @@ ); Менеджер = Новый МенеджерПараметров; - Менеджер.ИспользоватьПровайдерJSON(); - Менеджер.УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "cfg"); Менеджер.Прочитать(); @@ -400,8 +414,9 @@ ); Менеджер = Новый МенеджерПараметров; - Менеджер.ИспользоватьПровайдерJSON(); - Менеджер.УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "db"); Менеджер.Прочитать(); Менеджер.ЗаполнитьОбъектПараметров(ДТО, "db"); @@ -428,8 +443,9 @@ ); Менеджер = Новый МенеджерПараметров; - Менеджер.ИспользоватьПровайдерJSON(); - Менеджер.УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "cfg"); Менеджер.Прочитать(); Менеджер.ЗаполнитьОбъектПараметров(ДТО, "cfg");