protected void setListData(Collection<OBJECT_TYPE> items, boolean append, boolean forUpdate, boolean forceUpdateItems) {
        if (items == null) {
            return;
        }
        final Control itemsControl = itemsViewer.getControl();
        if (itemsControl.isDisposed()) {
            return;
        }

        itemsControl.setRedraw(false);
        try {
            final boolean reload = !append && (CommonUtils.isEmpty(objectList)) || (columnController == null);

            {
                // Collect list of items' classes
                final List<Class<?>> classList = new ArrayList<>();
                Class<?>[] baseTypes = getListBaseTypes(items);
                if (!ArrayUtils.isEmpty(baseTypes)) {
                    Collections.addAll(classList, baseTypes);
                }
                if (!CommonUtils.isEmpty(items)) {
                    for (OBJECT_TYPE item : items) {
                        Object object = getObjectValue(item);
                        if (object != null) {
                            Class<?> theClass = ObjectPropertyDescriptor.getObjectClass(object);
                            if (!classList.contains(theClass)) {
                                // Remove all base classes if we have sub class
                                // But keep interfaces because we may have multiple implementations of e.g. DBPNamedObject
                                // and we need to show "Name" instead of particular name props
                                for (int i = 0; i < classList.size(); i++) {
                                    Class<?> c = classList.get(i);
                                    if (!c.isInterface() && c.isAssignableFrom(theClass)) {
                                        classList.remove(i);
                                    } else {
                                        i++;
                                    }
                                }
                                classList.add(theClass);
                            }
                        }
                        if (isTree) {
                            Map<OBJECT_TYPE, Boolean> collectedSet = new IdentityHashMap<>();
                            collectItemClasses(item, classList, collectedSet);
                        }
                    }
                }

                IPropertyFilter propertyFilter = new DataSourcePropertyFilter(
                    ObjectListControl.this instanceof DBPDataSourceContainerProvider ?
                        ((DBPDataSourceContainerProvider) ObjectListControl.this).getDataSourceContainer() :
                        null);

                // Collect all properties
                PropertySourceAbstract propertySource = getListPropertySource();
                List<ObjectPropertyDescriptor> allProps = ObjectAttributeDescriptor.extractAnnotations(propertySource, classList, propertyFilter);
                if (!CommonUtils.isEmpty(items)) {
                    // Remove hidden properties (we need to check them against all items)
                    try {
                        allProps.removeIf(p -> {
                            for (OBJECT_TYPE item : items) {
                                Object objectValue = getObjectValue(item);
                                if (objectValue != null && p.isPropertyVisible(objectValue, objectValue)) {
                                    return false;
                                }
                            }
                            return true;
                        });
                    } catch (Throwable e) {
                        log.debug(e);
                    }
                }

                if (reload) {
                    clearListData();
                    columnController = new GroupingViewerColumnController<>(getListConfigId(classList), getItemsViewer());
                }

                // Create columns from classes' annotations
                for (ObjectPropertyDescriptor prop : allProps) {
                    if (!propertySource.hasProperty(prop)) {
                        if (prop.isOptional()) {
                            // Check whether at least one item has this property
                            boolean propHasValue = false;
                            if (!CommonUtils.isEmpty(items)) {
                                for (OBJECT_TYPE item : items) {
                                    try {
                                        Object propValue = prop.readValue(getObjectValue(item), null, true);
                                        if (propValue != null) {
                                            propHasValue = true;
                                            break;
                                        }
                                    } catch (Throwable e) {
                                        // Just ignore this
                                    }
                                }
                            }
                            if (!propHasValue) {
                                continue;
                            }
                        }
                        propertySource.addProperty(prop);
                        createColumn(prop);
                    }
                }
            }

            addExtraColumns(columnController, items);

            if (itemsControl.isDisposed()) {
                return;
            }
            if (reload) {
                columnController.createColumns(false);
            }
            if (reload || objectList.isEmpty()) {
                // Set viewer content
                objectList = createViewerInput(items);

                // Pack columns
                sampleItems = true;
                try {
                    List<OBJECT_TYPE> sampleList;
                    if (objectList.size() > 200) {
                        sampleList = objectList.subList(0, 100);
                    } else {
                        sampleList = objectList;
                    }
                    itemsViewer.setInput(createViewerInput(sampleList));

                    if (isTree) {
                        ((TreeViewer) itemsViewer).expandToLevel(4);
                    }
                    if (reload) {
                        columnController.repackColumns();
                    }
                } finally {
                    sampleItems = false;
                }
                // Set real content
                itemsViewer.setInput(objectList);
            } else if (items != null) {
                if (append) {
                    // Simply append new list to the tail
                    for (OBJECT_TYPE newObject : items) {
                        if (!objectList.contains(newObject)) {
                            objectList.add(newObject);
                        }
                    }
                } else {
                    // Update object list
                    if (!objectList.equals(items) || forceUpdateItems) {
                        int newListSize = items.size();
                        int itemIndex = 0;
                        for (OBJECT_TYPE newObject : items) {
                            if (itemIndex >= objectList.size()) {
                                // Add to tail
                                objectList.add(itemIndex, newObject);
                            } else {
                                OBJECT_TYPE oldObject = objectList.get(itemIndex);
                                if (!CommonUtils.equalObjects(oldObject, newObject) || forceUpdateItems) {
                                    // Replace old object
                                    objectList.set(itemIndex, newObject);
                                }
                            }
                            itemIndex++;
                        }
                        while (objectList.size() > newListSize) {
                            objectList.remove(objectList.size() - 1);
                        }
                    }
                }

                itemsViewer.refresh();
            }
        } finally {
            itemsControl.setRedraw(true);
        }
        setInfo(getItemsLoadMessage(objectList.size()));
    }
Used to save/load columns configuration.
Must depend on object types

@param classList classes of objects in the list
plugins/org.jkiss.dbeaver.ui.navigator/src/org/jkiss/dbeaver/ui/navigator/itemlist/ObjectListControl.java