Расширение Interactor

Архитектура вызова

Interactor.create создаёт JDK proxy только для переданного интерфейса. Цепочка вызова выглядит так:

метод интерфейса
  -> ValidationProxyHandler
  -> CacheProxyHandler
  -> InteractionDispatcher
  -> InteractionHandler
  -> сервисы и DAO через ServerContext

InteractionDispatcher хранит глобальный список фабрик. Для метода он берёт method.declaringClass, находит совместимый корневой интерфейс и выбирает обработчик по присутствующей на методе аннотации. Экземпляр обработчика создаётся конструктором (Int, ServerContext) и кешируется внутри dispatcher по сигнатуре метода.

Добавление обработчика

  1. Создайте runtime-аннотацию с @Target(AnnotationTarget.FUNCTION) и @MustBeDocumented.

  2. Реализуйте InteractionHandler либо BaseInteractionHandler<A>. Конструктор должен принимать objectId: Int и ServerContext.

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

  4. Зарегистрируйте пару «аннотация → обработчик» в каждой фабрике сущности, где операция действительно поддерживается.

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

  6. Обновите справочник обработчиков и матрицу сущностей.

Внешний модуль может зарегистрировать обработчик во время инициализации:

InteractionDispatcher.registerHandler<ProcessInteractor>(
    BindExternalValue::class.java,
    ExternalValueInteractionHandler::class.java
)

Повторная регистрация той же аннотации в фабрике запрещена.

Добавление сущности

  1. Создайте корневой интерфейс, наследующий Interactable.

  2. Создайте InteractionDispatcherFactory с type и таблицей mapping.

  3. Добавьте фабрику в начальный список InteractionDispatcher или зарегистрируйте через registerFactory при старте модуля.

  4. Добавьте базовый интерфейс с безопасными общеупотребительными методами.

  5. Покройте маршрутизацию и каждый обработчик unit-тестами.

  6. Обновите документацию сущностей и обработчиков.

registerFactory запрещает вторую фабрику для того же корневого типа. registerHandler принимает именно зарегистрированный корневой интерфейс; попытка регистрировать обработчик на его дочерний интерфейс завершается ошибкой.

Тесты

Базовые примеры находятся в core/src/test/java/ru/bgcrm/util/interactor:

  • InteractorDispatcherTest — выбор фабрики и регистрация;

  • CacheProxyHandlerTest — кеш и его сброс;

  • ValidationProxyHandlerTest и тесты валидаторов — входные и выходные ограничения;

  • handler/common/param — сигнатуры параметров;

  • handler/process и handler/tmc — процессные связи, статусы и интеграция TMC.

Для нового поведения недостаточно проверить только успешное чтение. Нужны регрессионные сценарии с null, пустой коллекцией, несколькими связанными объектами, изменением после кеширования и неверной сигнатурой.