5.5.12. Pluggable Component Factories
The pluggable component factories mechanism extends the standard component creation procedure and allows you to create different edit fields in FieldGroup, Table and DataGrid. It means that application components or your project itself can provide custom strategies that will create non-standard components and/or support custom data types.
An entry point to the mechanism is the ComponentsFactory.createComponent(ComponentGenerationContext) method. It works as follows:
-  
Tries to find
ComponentGenerationStrategyimplementations. If at least one strategy exists, then:-  
Iterates over strategies according to the
org.springframework.core.Orderedinterface. -  
Returns the first created not
nullcomponent. 
 -  
 
ComponentGenerationStrategy implementations are used to create UI components. A project can contain any number of such strategies.
ComponentGenerationContext is a class which stores the following information that can be used when creating a component:
-  
metaClass- defines the entity for which the component is created. -  
property- defines the entity attribute for which the component is created. -  
datasource- a datasource. -  
optionsDatasource- a datasource that can be used to show options. -  
xmlDescriptor- an XML descriptor which contains additional information, in case the component is declared in an XML descriptor. -  
componentClass- a component class for which a component is created, e.g.FieldGroup,Table,DataGrid. 
There are two built-in component strategies:
-  
DefaultComponentGenerationStrategy- used to create a component according to the givenComponentGenerationContextobject. Has the order valueComponentGenerationStrategy.LOWEST_PLATFORM_PRECEDENCE(1000). -  
DataGridEditorComponentGenerationStrategy- used to create a component according to the givenComponentGenerationContextobject for a DataGrid Editor. Has the order valueComponentGenerationStrategy.HIGHEST_PLATFORM_PRECEDENCE + 30(130). 
The sample below shows how to replace the default FieldGroup component generation for a certain attribute of a specific entity.
@Component(SalesComponentGenerationStrategy.NAME)
public class SalesComponentGenerationStrategy implements ComponentGenerationStrategy, Ordered {
    public static final String NAME = "sales_SalesComponentGenerationStrategy";
    @Inject
    private ComponentsFactory componentsFactory;
    @Inject
    private Metadata metadata;
    @Nullable
    @Override
    public Component createComponent(ComponentGenerationContext context) {
        String property = context.getProperty();
        MetaClass orderMetaClass = metadata.getClassNN(Order.class);
        // Check the specific field of the Order entity
        // and that the component is created for the FieldGroup component
        if (orderMetaClass.equals(context.getMetaClass())
                && "date".equals(property)
                && context.getComponentClass() != null
                && FieldGroup.class.isAssignableFrom(context.getComponentClass())) {
            DatePicker datePicker = componentsFactory.createComponent(DatePicker.class);
            Datasource datasource = context.getDatasource();
            if (datasource != null) {
                datePicker.setDatasource(datasource, property);
            }
            return datePicker;
        }
        return null;
    }
    @Override
    public int getOrder() {
        return 50;
    }
} 
  |  
       
        Warning 
         |  
      
       Pay attention that overriding existing generation strategies may produce errors in case of changing returned component type, because some screen controllers may have code that expects a certain component type. For example, in case of using the strategy above, the following injection will produce the exception:  
       If you try to open such screen you will get the following exception: IllegalArgumentException: Can not set com.haulmont.cuba.gui.components.DateField field com.company.sales.web.order.OrderEdit.dateField to com.haulmont.cuba.web.gui.components.WebDatePicker  |  
    
The sample below shows how to define a ComponentGenerationStrategy for a specific datatype.
@Order(100)
@Component(ColorComponentGenerationStrategy.NAME)
public class ColorComponentGenerationStrategy implements ComponentGenerationStrategy {
    public static final String NAME = "colordatatype_ColorComponentGenerationStrategy";
    @Inject
    private ComponentsFactory componentsFactory;
    @Nullable
    @Override
    public Component createComponent(ComponentGenerationContext context) {
        String property = context.getProperty();
        MetaPropertyPath mpp = resolveMetaPropertyPath(context.getMetaClass(), property);
        if (mpp != null) {
            Range mppRange = mpp.getRange();
            if (mppRange.isDatatype()
                    && ((Datatype) mppRange.asDatatype()) instanceof ColorDatatype) {
                ColorPicker colorPicker = componentsFactory.createComponent(ColorPicker.class);
                colorPicker.setDefaultCaptionEnabled(true);
                Datasource datasource = context.getDatasource();
                if (datasource != null) {
                    colorPicker.setDatasource(datasource, property);
                }
                return colorPicker;
            }
        }
        return null;
    }
    protected MetaPropertyPath resolveMetaPropertyPath(MetaClass metaClass, String property) {
        MetaPropertyPath mpp = metaClass.getPropertyPath(property);
        if (mpp == null && DynamicAttributesUtils.isDynamicAttribute(property)) {
            mpp = DynamicAttributesUtils.getMetaPropertyPath(metaClass, property);
        }
        return mpp;
    }
}