vaadin / framework

Vaadin 6, 7, 8 is a Java framework for modern Java web applications.
http://vaadin.com/
Other
1.78k stars 729 forks source link

CallbackDataProvider cannot be cast to custom DataProvider #12394

Closed samo4b closed 2 years ago

samo4b commented 3 years ago

We tried to move from Vaadin 8.8.5 to 8.13.3 and encountered the following issue: The method internalSetDataProvider of the class com.vaadin.ui.Grid has changed and does not work with our custom DataProvider anymore.

Method internalSetDataProvider from the specific Vaadin 8 Versions: Vaadin 8.8.5 (method is still the same up to 8.12.4)

@Override
protected void internalSetDataProvider(DataProvider<T, ?> dataProvider) {
    super.internalSetDataProvider(dataProvider);
    for (Column<T, ?> column : getColumns()) {
        column.updateSortable();
    }
}

Vaadin 8.13.0 and newer (up to 8.13.3)

@Override
protected void internalSetDataProvider(DataProvider<T, ?> dataProvider) {
    boolean newProvider = getDataProvider() != dataProvider;
    super.internalSetDataProvider(dataProvider);
    if (newProvider) {
        Set<T> oldVisibleDetails = new HashSet<>(
                detailsManager.visibleDetails);
        oldVisibleDetails.forEach(item -> {
            // close all old details even if the same item exists in the new
            // provider
            detailsManager.setDetailsVisible(item, false);
        });
    }
    for (Column<T, ?> column : getColumns()) {
        column.updateSortable();
    }
}

Explanation why I think this is a bug: The method internalSetDataProvider does allow us to set a custom data provider of the interface type DataProvider. But when I provide a DataProvider which does not implement CallbackDataProvider or AbstractBackEndDataProvider I get an exception:

Caused by: java.lang.ClassCastException: com.vaadin.data.provider.CallbackDataProvider cannot be cast to net.example.JavaListValueDataProvider

I assume this is because the check does try to compare the new DataProvider with the default one and fails the cast of the data types.

boolean newProvider = getDataProvider() != dataProvider;

Our DataProvider class looks like the following: As you can see it does implement DataProvider over AbstractDataProvider but cannot be cast to CallbackDataProvider

public class JavaListValueDataProvider<T extends JavaValueDataInterface>
extends
    AbstractDataProvider<T, SerializablePredicate<T>>
implements
    InMemoryDataProvider<T> {
...
}
pinneri commented 3 years ago

This falls into: don't call an overridable method in your constructor. Instead of calling getDataProvider() they should call internalGetDataProvider()

samo4b commented 2 years ago

Sorry I did not find the time to answer sooner I think this is resolved by the other Pull Request.