Skip to content

Commit

Permalink
Add static helpers for creating callback data providers (#8314)
Browse files Browse the repository at this point in the history
Cannot overload the same create method for this purpose since it
conflicts with T... overload. Each case is instead given its own
descriptive but still discoverable method name.
  • Loading branch information
Legioth committed Jan 25, 2017
1 parent 0f350c6 commit 8300e3e
Show file tree
Hide file tree
Showing 18 changed files with 108 additions and 55 deletions.
2 changes: 1 addition & 1 deletion server/src/main/java/com/vaadin/data/HasDataProvider.java
Expand Up @@ -54,7 +54,7 @@ public interface HasDataProvider<T> extends HasItems<T> {


@Override @Override
public default void setItems(Collection<T> items) { public default void setItems(Collection<T> items) {
setDataProvider(DataProvider.create(items)); setDataProvider(DataProvider.ofCollection(items));
} }


} }
Expand Up @@ -45,8 +45,8 @@ public class CallbackDataProvider<T, F>
* function that returns a stream of items from the back end for * function that returns a stream of items from the back end for
* a query * a query
* @param sizeCallback * @param sizeCallback
* function that return the number of items in the back end for a * function that returns the number of items in the back end for
* query * a query
*/ */
public CallbackDataProvider( public CallbackDataProvider(
SerializableFunction<Query<T, F>, Stream<T>> fetchCallback, SerializableFunction<Query<T, F>, Stream<T>> fetchCallback,
Expand Down
86 changes: 67 additions & 19 deletions server/src/main/java/com/vaadin/data/provider/DataProvider.java
Expand Up @@ -26,6 +26,7 @@
import com.vaadin.data.HasFilterableDataProvider; import com.vaadin.data.HasFilterableDataProvider;
import com.vaadin.server.SerializableBiFunction; import com.vaadin.server.SerializableBiFunction;
import com.vaadin.server.SerializableFunction; import com.vaadin.server.SerializableFunction;
import com.vaadin.server.SerializableToIntFunction;
import com.vaadin.shared.Registration; import com.vaadin.shared.Registration;


/** /**
Expand All @@ -47,9 +48,11 @@
* @param <F> * @param <F>
* filter type * filter type
* *
* @see #create(Collection) * @see #ofCollection(Collection)
* @see #create(Stream) * @see #ofItems(Object...)
* @see #create(Object...) * @see #fromStream(Stream)
* @see #fromCallbacks(SerializableFunction, SerializableToIntFunction)
* @see #fromFilteringCallbacks(SerializableFunction, SerializableToIntFunction)
* @see ListDataProvider * @see ListDataProvider
* @see BackEndDataProvider * @see BackEndDataProvider
* *
Expand Down Expand Up @@ -193,24 +196,27 @@ public default ConfigurableFilterDataProvider<T, Void, F> withConfigurableFilter
} }


/** /**
* This method creates a new {@link ListDataProvider} from a given * Creates a new data provider backed by a collection.
* Collection. The ListDataProvider creates a protective List copy of all * <p>
* the contents in the Collection. * The collection is used as-is. Changes in the collection will be visible
* via the created data provider. The caller should copy the collection if
* necessary.
* *
* @param <T> * @param <T>
* the data item type * the data item type
* @param items * @param items
* the collection of data, not null * the collection of data, not <code>null</code>
* @return a new list data provider * @return a new list data provider
*/ */
public static <T> ListDataProvider<T> create(Collection<T> items) { public static <T> ListDataProvider<T> ofCollection(Collection<T> items) {
return new ListDataProvider<>(items); return new ListDataProvider<>(items);
} }


/** /**
* This method creates a new {@link ListDataProvider} from given objects.The * Creates a new data provider from the given items.
* ListDataProvider creates a protective List copy of all the contents in * <p>
* the array. * The items are copied into a new backing list, so structural changes to
* the provided array will not be visible via the created data provider.
* *
* @param <T> * @param <T>
* the data item type * the data item type
Expand All @@ -219,30 +225,72 @@ public static <T> ListDataProvider<T> create(Collection<T> items) {
* @return a new list data provider * @return a new list data provider
*/ */
@SafeVarargs @SafeVarargs
public static <T> ListDataProvider<T> create(T... items) { public static <T> ListDataProvider<T> ofItems(T... items) {
return new ListDataProvider<>(Arrays.asList(items)); return new ListDataProvider<>(Arrays.asList(items));
} }


/** /**
* This method creates a new {@link ListDataProvider} from the given stream. * Creates a new data provider from the given stream. <b>All items in the
* The ListDataProvider <b>collects all the items in the stream to a * stream are eagerly collected to a list.</b>
* list</b>.
* <p> * <p>
* This is just a shorthand for using {@link #create(Collection)} after * This is a shorthand for using {@link #ofCollection(Collection)} after
* collecting the items in the stream to a list with e.g. * collecting the items in the stream to a list with e.g.
* {@code stream.collect(Collectors.toList));}. * {@code stream.collect(Collectors.toList));}.
* <p> * <p>
* <strong>Using big streams is not recommended, you should instead use a * <strong>Using big streams is not recommended, you should instead use a
* lazy data provider.</strong> See {@link BackEndDataProvider} for more * lazy data provider.</strong> See
* info. * {@link #fromCallbacks(SerializableFunction, SerializableToIntFunction)}
* or {@link BackEndDataProvider} for more info.
* *
* @param <T> * @param <T>
* the data item type * the data item type
* @param items * @param items
* a stream of data items, not {@code null} * a stream of data items, not {@code null}
* @return a new list data provider * @return a new list data provider
*/ */
public static <T> ListDataProvider<T> create(Stream<T> items) { public static <T> ListDataProvider<T> fromStream(Stream<T> items) {
return new ListDataProvider<>(items.collect(Collectors.toList())); return new ListDataProvider<>(items.collect(Collectors.toList()));
} }

/**
* Creates a new data provider that uses filtering callbacks for fetching
* and counting items from any backing store.
* <p>
* The query that is passed to each callback may contain a filter value that
* is provided by the component querying for data.
*
* @param fetchCallback
* function that returns a stream of items from the back end for
* a query
* @param sizeCallback
* function that returns the number of items in the back end for
* a query
* @return a new callback data provider
*/
public static <T, F> CallbackDataProvider<T, F> fromFilteringCallbacks(
SerializableFunction<Query<T, F>, Stream<T>> fetchCallback,
SerializableToIntFunction<Query<T, F>> sizeCallback) {
return new CallbackDataProvider<>(fetchCallback, sizeCallback);
}

/**
* Creates a new data provider that uses callbacks for fetching and counting
* items from any backing store.
* <p>
* The query that is passed to each callback will not contain any filter
* values.
*
* @param fetchCallback
* function that returns a stream of items from the back end for
* a query
* @param sizeCallback
* function that returns the number of items in the back end for
* a query
* @return a new callback data provider
*/
public static <T> CallbackDataProvider<T, Void> fromCallbacks(
SerializableFunction<Query<T, Void>, Stream<T>> fetchCallback,
SerializableToIntFunction<Query<T, Void>> sizeCallback) {
return fromFilteringCallbacks(fetchCallback, sizeCallback);
}
} }
2 changes: 1 addition & 1 deletion server/src/main/java/com/vaadin/ui/CheckBoxGroup.java
Expand Up @@ -84,7 +84,7 @@ public CheckBoxGroup(String caption, DataProvider<T, ?> dataProvider) {
* @see #setItems(Collection) * @see #setItems(Collection)
*/ */
public CheckBoxGroup(String caption, Collection<T> items) { public CheckBoxGroup(String caption, Collection<T> items) {
this(caption, DataProvider.create(items)); this(caption, DataProvider.ofCollection(items));
} }


/** /**
Expand Down
4 changes: 2 additions & 2 deletions server/src/main/java/com/vaadin/ui/ComboBox.java
Expand Up @@ -219,7 +219,7 @@ private void init() {
*/ */
@Override @Override
public void setItems(Collection<T> items) { public void setItems(Collection<T> items) {
ListDataProvider<T> listDataProvider = DataProvider.create(items); ListDataProvider<T> listDataProvider = DataProvider.ofCollection(items);


setDataProvider(listDataProvider); setDataProvider(listDataProvider);
} }
Expand Down Expand Up @@ -285,7 +285,7 @@ public void setDataProvider(ListDataProvider<T> listDataProvider) {
* the data items to display * the data items to display
*/ */
public void setItems(CaptionFilter captionFilter, Collection<T> items) { public void setItems(CaptionFilter captionFilter, Collection<T> items) {
ListDataProvider<T> listDataProvider = DataProvider.create(items); ListDataProvider<T> listDataProvider = DataProvider.ofCollection(items);


setDataProvider(captionFilter, listDataProvider); setDataProvider(captionFilter, listDataProvider);
} }
Expand Down
2 changes: 1 addition & 1 deletion server/src/main/java/com/vaadin/ui/ListSelect.java
Expand Up @@ -77,7 +77,7 @@ public ListSelect(String caption, DataProvider<T, ?> dataProvider) {
* the options, cannot be {@code null} * the options, cannot be {@code null}
*/ */
public ListSelect(String caption, Collection<T> options) { public ListSelect(String caption, Collection<T> options) {
this(caption, DataProvider.create(options)); this(caption, DataProvider.ofCollection(options));
} }


/** /**
Expand Down
2 changes: 1 addition & 1 deletion server/src/main/java/com/vaadin/ui/RadioButtonGroup.java
Expand Up @@ -93,7 +93,7 @@ public RadioButtonGroup(String caption, DataProvider<T, ?> dataProvider) {
* @see #setItems(Collection) * @see #setItems(Collection)
*/ */
public RadioButtonGroup(String caption, Collection<T> items) { public RadioButtonGroup(String caption, Collection<T> items) {
this(caption, DataProvider.create(items)); this(caption, DataProvider.ofCollection(items));
} }


/** /**
Expand Down
2 changes: 1 addition & 1 deletion server/src/main/java/com/vaadin/ui/TwinColSelect.java
Expand Up @@ -74,7 +74,7 @@ public TwinColSelect(String caption, DataProvider<T, ?> dataProvider) {
* the options, cannot be {@code null} * the options, cannot be {@code null}
*/ */
public TwinColSelect(String caption, Collection<T> options) { public TwinColSelect(String caption, Collection<T> options) {
this(caption, DataProvider.create(options)); this(caption, DataProvider.ofCollection(options));
} }


/** /**
Expand Down
Expand Up @@ -16,7 +16,7 @@ public class ListDataProviderTest


@Override @Override
protected ListDataProvider<StrBean> createDataProvider() { protected ListDataProvider<StrBean> createDataProvider() {
return DataProvider.create(data); return DataProvider.ofCollection(data);
} }


@Test @Test
Expand Down
Expand Up @@ -25,7 +25,6 @@
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;


import com.vaadin.data.provider.CallbackDataProvider;
import com.vaadin.data.provider.DataProvider; import com.vaadin.data.provider.DataProvider;
import com.vaadin.data.provider.SortOrder; import com.vaadin.data.provider.SortOrder;
import com.vaadin.shared.data.sort.SortDirection; import com.vaadin.shared.data.sort.SortDirection;
Expand Down Expand Up @@ -102,7 +101,7 @@ public void testPersons() {
} }


private DataProvider<Person, ?> createUnsortedDataProvider() { private DataProvider<Person, ?> createUnsortedDataProvider() {
DataProvider<Person, ?> dataProvider = new CallbackDataProvider<>( DataProvider<Person, ?> dataProvider = DataProvider.fromCallbacks(
// First callback fetches items based on a query // First callback fetches items based on a query
query -> { query -> {
// The index of the first item to load // The index of the first item to load
Expand Down Expand Up @@ -130,7 +129,7 @@ public void testSortedPersons() {
} }


private DataProvider<Person, ?> createSortedDataProvider() { private DataProvider<Person, ?> createSortedDataProvider() {
DataProvider<Person, ?> dataProvider = new CallbackDataProvider<>( DataProvider<Person, ?> dataProvider = DataProvider.fromCallbacks(
// First callback fetches items based on a query // First callback fetches items based on a query
query -> { query -> {
List<PersonService.PersonSort> sortOrders = new ArrayList<>(); List<PersonService.PersonSort> sortOrders = new ArrayList<>();
Expand Down
Expand Up @@ -24,7 +24,7 @@
import org.junit.Test; import org.junit.Test;
import org.mockito.Mockito; import org.mockito.Mockito;


import com.vaadin.data.provider.CallbackDataProvider; import com.vaadin.data.provider.DataProvider;
import com.vaadin.data.provider.bov.Person; import com.vaadin.data.provider.bov.Person;
import com.vaadin.event.selection.MultiSelectionEvent; import com.vaadin.event.selection.MultiSelectionEvent;
import com.vaadin.event.selection.MultiSelectionListener; import com.vaadin.event.selection.MultiSelectionListener;
Expand Down Expand Up @@ -664,13 +664,15 @@ public void selectAllCheckboxVisible__lazyDataProvider() {
model.getSelectAllCheckBoxVisibility()); model.getSelectAllCheckBoxVisibility());


grid.setDataProvider( grid.setDataProvider(
new CallbackDataProvider<String, String>( DataProvider
q -> IntStream .fromCallbacks(
.range(q.getOffset(), query -> IntStream
Math.max(q.getOffset() + q.getLimit() .range(query.getOffset(),
+ 1, 1000)) Math.max(query.getOffset()
.mapToObj(i -> "Item " + i), + query.getLimit() + 1,
q -> 1000)); 1000))
.mapToObj(i -> "Item " + i),
query -> 1000));


// not in-memory -> checkbox is hidden // not in-memory -> checkbox is hidden
Assert.assertFalse(model.isSelectAllCheckBoxVisible()); Assert.assertFalse(model.isSelectAllCheckBoxVisible());
Expand Down
Expand Up @@ -123,7 +123,8 @@ public void setListDataProvider_defaultFiltering() {


// Result: typing "en" into the search field finds "Enrique Iglesias" // Result: typing "en" into the search field finds "Enrique Iglesias"
// and "Henry Dunant", but not "Erwin Engelbrecht" // and "Henry Dunant", but not "Erwin Engelbrecht"
comboBox.setDataProvider(DataProvider.create(getPersonCollection())); comboBox.setDataProvider(
DataProvider.ofCollection(getPersonCollection()));


checkFiltering("en", "ennen", 3, 2); checkFiltering("en", "ennen", 3, 2);
} }
Expand All @@ -135,13 +136,14 @@ public void setListDataProvider_customFiltering() {
// Result: typing "En" into the search field finds "Enrique Iglesias" // Result: typing "En" into the search field finds "Enrique Iglesias"
// but not "Henry Dunant" or "Erwin Engelbrecht" // but not "Henry Dunant" or "Erwin Engelbrecht"
comboBox.setDataProvider(String::startsWith, comboBox.setDataProvider(String::startsWith,
DataProvider.create(getPersonCollection())); DataProvider.ofCollection(getPersonCollection()));


checkFiltering("En", "en", 3, 1); checkFiltering("En", "en", 3, 1);
} }


public void invalid_dataProvider_compile_error() { public void invalid_dataProvider_compile_error() {
DataProvider<Person, Address> dp = DataProvider.create(getPersonArray()) DataProvider<Person, Address> dp = DataProvider
.ofItems(getPersonArray())
.filteringByEquals(Person::getAddress); .filteringByEquals(Person::getAddress);


// uncommenting this causes a compile time error because of invalid data // uncommenting this causes a compile time error because of invalid data
Expand All @@ -154,7 +156,7 @@ public void customDataProvider_filterByLastName() {
comboBox.setItemCaptionGenerator(Person::getFirstName); comboBox.setItemCaptionGenerator(Person::getFirstName);


// Filters by last name, regardless of the item caption generator // Filters by last name, regardless of the item caption generator
ListDataProvider<Person> ldp = DataProvider.create(getPersonArray()); ListDataProvider<Person> ldp = DataProvider.ofItems(getPersonArray());
comboBox.setDataProvider(ldp.withConvertedFilter( comboBox.setDataProvider(ldp.withConvertedFilter(
text -> person -> person.getLastName().contains(text))); text -> person -> person.getLastName().contains(text)));


Expand All @@ -166,7 +168,7 @@ public void customDataProvider_filterByLastNameWithAccessRestriction() {
comboBox.setItemCaptionGenerator(Person::getFirstName); comboBox.setItemCaptionGenerator(Person::getFirstName);


// Filters by last name, regardless of the item caption generator // Filters by last name, regardless of the item caption generator
ListDataProvider<Person> ldp = DataProvider.create(getPersonArray()); ListDataProvider<Person> ldp = DataProvider.ofItems(getPersonArray());
ldp.setFilter(person -> person.getFirstName().contains("nr")); ldp.setFilter(person -> person.getFirstName().contains("nr"));


// Same as above, but only showing a subset of the persons // Same as above, but only showing a subset of the persons
Expand Down
12 changes: 7 additions & 5 deletions server/src/test/java/com/vaadin/ui/AbstractListingTest.java
Expand Up @@ -12,7 +12,6 @@
import org.junit.Test; import org.junit.Test;


import com.vaadin.data.HasDataProvider; import com.vaadin.data.HasDataProvider;
import com.vaadin.data.provider.CallbackDataProvider;
import com.vaadin.data.provider.DataProvider; import com.vaadin.data.provider.DataProvider;
import com.vaadin.data.provider.ListDataProvider; import com.vaadin.data.provider.ListDataProvider;
import com.vaadin.data.provider.Query; import com.vaadin.data.provider.Query;
Expand Down Expand Up @@ -109,13 +108,16 @@ public void testSetItemsWithVarargs() {


@Test @Test
public void testSetDataProvider() { public void testSetDataProvider() {
ListDataProvider<String> dataProvider = DataProvider.create(items); ListDataProvider<String> dataProvider = DataProvider
.ofCollection(items);
listing.setDataProvider(dataProvider); listing.setDataProvider(dataProvider);
Assert.assertEquals("setDataProvider did not set data provider", Assert.assertEquals("setDataProvider did not set data provider",
dataProvider, listing.getDataProvider()); dataProvider, listing.getDataProvider());
listing.setDataProvider(new CallbackDataProvider<>(q -> Stream listing.setDataProvider(
.of(ITEM_ARRAY).skip(q.getOffset()).limit(q.getLimit()), DataProvider.fromCallbacks(
q -> ITEM_ARRAY.length)); query -> Stream.of(ITEM_ARRAY).skip(query.getOffset())
.limit(query.getLimit()),
query -> ITEM_ARRAY.length));
Assert.assertNotEquals("setDataProvider did not replace data provider", Assert.assertNotEquals("setDataProvider did not replace data provider",
dataProvider, listing.getDataProvider()); dataProvider, listing.getDataProvider());
} }
Expand Down
Expand Up @@ -35,7 +35,7 @@ public void setUp() {
radioButtonGroup = new RadioButtonGroup<>(); radioButtonGroup = new RadioButtonGroup<>();
// Intentional deviation from upcoming selection order // Intentional deviation from upcoming selection order
radioButtonGroup.setDataProvider( radioButtonGroup.setDataProvider(
DataProvider.create("Third", "Second", "First")); DataProvider.ofItems("Third", "Second", "First"));
} }


@Test @Test
Expand Down
Expand Up @@ -79,7 +79,7 @@ private Grid<Person> createGrid(boolean withData) {
grid.setSelectionMode(selectionMode); grid.setSelectionMode(selectionMode);


items = new ArrayList<>(); items = new ArrayList<>();
provider = DataProvider.create(items); provider = DataProvider.ofCollection(items);
grid.setDataProvider(provider); grid.setDataProvider(provider);


if (withData) { if (withData) {
Expand Down
Expand Up @@ -37,7 +37,7 @@ protected void setup(VaadinRequest request) {
persons = createPersons(10, new Random(1)); persons = createPersons(10, new Random(1));


grid = new Grid<>(); grid = new Grid<>();
ListDataProvider<ComplexPerson> provider = DataProvider.create(persons); ListDataProvider<ComplexPerson> provider = DataProvider.ofCollection(persons);
grid.setDataProvider(provider); grid.setDataProvider(provider);
grid.getSelectionModel().select(persons.get(0)); grid.getSelectionModel().select(persons.get(0));
addComponent(new Button("Remove first", event -> { addComponent(new Button("Remove first", event -> {
Expand Down
Expand Up @@ -35,7 +35,7 @@ protected void setup(VaadinRequest request) {
Grid<DataObject> grid = new Grid<>(); Grid<DataObject> grid = new Grid<>();
List<DataObject> data = DataObject.generateObjects(); List<DataObject> data = DataObject.generateObjects();


ListDataProvider<DataObject> dataProvider = DataProvider.create(data); ListDataProvider<DataObject> dataProvider = DataProvider.ofCollection(data);
grid.setDataProvider(dataProvider); grid.setDataProvider(dataProvider);


grid.setDataProvider(dataProvider); grid.setDataProvider(dataProvider);
Expand Down
Expand Up @@ -107,7 +107,7 @@ public static ListDataProvider<ComplexPerson> createDataProvider(int size) {
list.add(cp); list.add(cp);
} }


return DataProvider.create(list); return DataProvider.ofCollection(list);
} }


public static ComplexPerson create(Random r) { public static ComplexPerson create(Random r) {
Expand Down

0 comments on commit 8300e3e

Please sign in to comment.