Динамическое (программное) создание фильтра

Добрый день.
Есть такая задачка: Отобразить данные из сырого SQL запроса в таблице (например, GroupTable) с различными ее бонусами вроде панели кнопок, пагинации и т.п.

Порядок выполнения примерно такой:

// Загрузка данных в список по SQL запросу
List<Map<String, Object>> list = jdbcTemplate.queryForList(sqlQuery); 

// container создается аналогично примеру
// https://demo.jmix.io/sampler/#main/4/sample?id=datagrid-var-columns
var keyValueList = list.stream().map(mp -> {
    KeyValueEntity entity = new KeyValueEntity();
    mp.forEach((key, val) -> {
        // тут groupTable.setItems() ругался, что не может привести Integer к String,
        // поэтому вручную привел к String все значения
        entity.setValue(key, val != null ? val.toString() : null); 
    });
    return entity;
}).toList();

KeyValueCollectionContainer container = dataComponents.createKeyValueCollectionContainer();
columns.forEach(col -> container.addProperty(col, String.class));
container.setItems(entities);

// Создание таблицы и установка контейнера с значениями
GroupTable<KeyValueEntity> groupTable = uiComponents.create(GroupTable.class);
groupTable.setItems(new ContainerGroupTableItems<>(container));

Код выше вроде как корректно отображает данные в таблице.

Теперь я пытаюсь создать фильтр на основе примера https://demo.jmix.io/sampler/#main/5/sample?id=filter-programmatically-defined либо Filter :: Jmix Documentation .

filter = uiComponents.create(Filter.NAME);
filter.setId("filter");

KeyValueCollectionLoader dataLoader = new KeyValueCollectionLoaderImpl();
dataLoader.setContainer(container); // на этом месте выпадает ошибка (указана ниже)
filter.setDataLoader(dataLoader); // а тут в примере подсовывают уже injected CollectionLoader из таблицы с xml разметки

Ошибка: NullPointerException: Cannot invoke “io.jmix.ui.model.SorterFactory.createCollectionContainerSorter(io.jmix.ui.model.CollectionContainer, io.jmix.ui.model.BaseCollectionLoader)” because “this.sorterFactory” is null

image

В принципе ошибка очевидна, ведь я создал пустой инстанс (фото выше). Хотя в коде KeyValueCollectionLoaderImpl этот самый sorterFactory это бин

@Autowired
protected SorterFactory sorterFactory;

Подскажите, если в коде выше нет ошибок, может быть можно программно создать KeyValueCollectionLoader либо обычный CollectionLoader, чтобы он подхватил нужные зависимости? Ну или как минимум позволил запихнуть в него мой контейнер.

Глобально задача - добавить фильтр, так что может быть есть и другой способ?
Заранее спасибо :slight_smile:

P.S.
Пагинация тоже не особо работает:

SimplePagination paginationComponent = uiComponents.create(SimplePagination.class);

paginationComponent.setAlignment(io.jmix.ui.component.Component.Alignment.MIDDLE_RIGHT);
paginationComponent.setItemsPerPageVisible(true);
paginationComponent.setItemsPerPageDefaultValue(500);
paginationComponent.setItemsPerPageUnlimitedOptionVisible(true);
// paginationComponent.setTotalCountDelegate(() -> groupTable.getItems().size());
paginationComponent.setAutoLoad(true);
groupTable.setPagination(paginationComponent);

Максимум, что делает - выставляет число 500. Попадались решения в виде @install для таблиц из коллекций на основе Entity, но у меня, насколько я понимаю, нестандартный случай программной keyValue
Будет круто, если подскажите с пагинацией тоже)

Так вы создали бин через вызов конструктора. Спринг его не подхватывает.
В ScreenDataXmlLoader#loadKeyValueCollectionLoader происходит создание KeyValueCollectionLoader через DataComponents#createKeyValueCollectionLoader можете попробовать использовать его для создания загрузчика и контейнера. В этом методе происходит autowire

Тут не ясно что конкретно вы хотите. У вас нет кнопок переключения страниц? Или они не активны? Если не активны, то мб у вас загружены все записи из бд?
Можете посмотреть как создается объект из дескриптора в загрузчиках, классы SimplePaginationLoader и AbstractPaginationLoader, мб вы чего не установили.

Скорее всего из-за того что загрузчика у вас на данный момент нет. Он и не работает как вы рассчитываете.

Да и там надо будет переопределить TotalCountDelegate чтоб тот возвращал скок всего записей в таблице что вы используете в sqlQuery и у загрузчика добавить loadDelegete с вашей логикой загрузки из jdbcTemplate, нужно будет брать firstResult и maxResults из LoadContext.query и возвращать соответсвенные страницы для правильной работы SimplePagination.

И если у вас будет фильтр из LoadContext.query брать condition парсить его и ставить в sqlQuery

1 симпатия