Подключаемые фабрики компонентов

Механизм подключаемых фабрик компонентов расширяет процедуру генерации компонентов и позволяет создавать различные поля редактирования в Form, Table и DataGrid. Это означает, что компоненты приложения или сам ваш проект могут предоставлять собственные стратегии, которые будут создавать нестандартные компоненты и/или поддерживать кастомные типы данных.

Точкой входа в данный механизм является метод UiComponentsGenerator.generate(ComponentGenerationContext). Сначала он пытается найти все реализации интерфейса ComponentGenerationStrategy. Если как минимум одна реализация существует, то он обходит все реализации в соответствии с интерфейсом org.springframework.core.Ordered и возвращает первый созданный не нулевой компонент.

Реализации интерфейса ComponentGenerationStrategy используются при создании UI компонентов. Проект может содержать любое количество таких стратегий.

ComponentGenerationContext – класс, содержащий следующую информацию, которая может быть использована при создании компонента:

  • metaClass - задает сущность, для которой создается компонент.

  • property - задает атрибут сущности, для которой создается компонент.

  • valueSource - источник данных, который может быть связан с компонентом.

  • options - источник данных, который может быть связан с компонентом для показа опций.

  • xmlDescriptor - XML-дескриптор с дополнительной информацией, в случае, если компонент объявлен в XML-дескрипторе.

  • targetClass - целевой класс, для которого должен быть создан компонент, например Form, Table, DataGrid.

Существуют две встроенные стратегии:

  • DefaultComponentGenerationStrategy используется для создания компонентов в соответствии с переданным объектом ComponentGenerationContext. Имеет значение order равное JmixOrder.LOWEST_PLATFORM_PRECEDENCE (1000). Более высокие значения интерпретируются как имеющие более низкий приоритет; самое низкое значение имеет самый высокий приоритет; одинаковые значения order приведут к произвольным позициям сортировки для затронутых объектов.

  • CustomDatatypesComponentGenerationStrategy предназначена для генерации поля по умолчанию в соответствии с datatype, для которого не создали поле другие стратегии генерации. Например, если datatype является кастомным и не соответствует ни одному типу, для которого создает поля DefaultComponentGenerationStrategy. Имеет значение order равное Integer.MAX_VALUE (0x7fffffff).

Пример ниже показывает, как заменить стандартную генерацию поля в компоненте Form для определенного атрибута некоторой сущности.

@org.springframework.stereotype.Component("sample_SalesComponentGenerationStrategy")
public class SalesComponentGenerationStrategy implements ComponentGenerationStrategy, Ordered {

    @Inject
    private UiComponents uiComponents;

    @Inject
    private Metadata metadata;

    @Nullable
    @Override
    public Component createComponent(ComponentGenerationContext context) {
        String property = context.getProperty();
        MetaClass orderMetaClass = metadata.getClass(Order.class);

        if (orderMetaClass.equals(context.getMetaClass())
                && "date".equals(property) (1)
                && context.getClass() != null
                && Form.class.isAssignableFrom(context.getClass())) { (2)
            DatePicker<Date> datePicker = uiComponents.create(DatePicker.TYPE_DATE); (3)

            ValueSource valueSource = context.getValueSource();
            if (valueSource != null) {
                datePicker.setValueSource(valueSource); (4)
            }

            return datePicker;
        }

        return null;
    }

    @Override
    public int getOrder() {
        return 50; (5)
    }
}
1 Проверяет конкретное поле сущности Order.
2 Проверяет, что компонент создан для компонента Form.
3 Создает конкретный компонент DatePicker.
4 Привязывает компонент к источнику данных.
5 Возвращает значение order этого объекта.

Пример ниже показывает, как определить ComponentGenerationStrategy для некоторого datatype.

@Order(100)
@org.springframework.stereotype.Component("sample_ColorComponentGenerationStrategy")
public class ColorComponentGenerationStrategy implements ComponentGenerationStrategy {

    @Inject
    private UiComponents uiComponents;

    @Nullable
    @Override
    public Component createComponent(ComponentGenerationContext context) {
        String property = context.getProperty();
        MetaPropertyPath mpp = context.getMetaClass().getPropertyPath(property);

        if (mpp != null) {
            Range mppRange = mpp.getRange();
            if (mppRange.isDatatype()
                    && (Datatype) mppRange.asDatatype() instanceof ColorDatatype) {
                ColorPicker colorPicker = uiComponents.create(ColorPicker.class);
                colorPicker.setDefaultCaptionEnabled(true);

                ValueSource valueSource = context.getValueSource();
                if (valueSource != null) {
                    colorPicker.setValueSource(valueSource);
                }
                return colorPicker;
            }
        }
        return null;
    }

}