From 3f37f893cbebebc3c9ddbeaaedba4658026428f0 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Leif=20=C3=85strand?= Date: Fri, 21 Oct 2016 11:11:27 +0300 Subject: [PATCH] Correct serializable issues and test that components can be serialized Change-Id: Iac8f0f48806c0a7c3030bd406e2e533104f26753 --- .../main/java/com/vaadin/data/BeanBinder.java | 21 ++-- .../src/main/java/com/vaadin/data/Binder.java | 61 +++++----- .../main/java/com/vaadin/data/Validator.java | 4 +- .../vaadin/data/util/converter/Converter.java | 13 +- .../data/validator/AbstractValidator.java | 4 +- .../vaadin/server/SerializableBiConsumer.java | 38 ++++++ .../vaadin/server/SerializableComparator.java | 49 ++++++++ .../vaadin/server/SerializableFunction.java | 46 +++++++ .../vaadin/server/SerializablePredicate.java | 32 +++++ .../vaadin/server/data/BackEndDataSource.java | 11 +- .../vaadin/server/data/DataCommunicator.java | 5 +- .../com/vaadin/ui/AbstractMultiSelect.java | 14 ++- .../java/com/vaadin/ui/CheckBoxGroup.java | 7 +- server/src/main/java/com/vaadin/ui/Grid.java | 44 ++++--- .../java/com/vaadin/ui/IconGenerator.java | 6 +- .../com/vaadin/ui/ItemCaptionGenerator.java | 5 +- .../java/com/vaadin/ui/RadioButtonGroup.java | 9 +- .../java/com/vaadin/ui/StyleGenerator.java | 5 +- .../data/BinderConverterValidatorTest.java | 5 +- .../tests/data/converter/ConverterTest.java | 8 +- .../tests/server/ClassesSerializableTest.java | 114 ++++++++++++++---- .../component/grid/GridDefaultHeaderTest.java | 18 ++- .../component/grid/GridHeaderFooterTest.java | 9 +- .../tests/server/component/grid/GridTest.java | 7 +- .../grid/GridApplyFilterWhenScrolledDown.java | 4 +- 25 files changed, 402 insertions(+), 137 deletions(-) create mode 100644 server/src/main/java/com/vaadin/server/SerializableBiConsumer.java create mode 100644 server/src/main/java/com/vaadin/server/SerializableComparator.java create mode 100644 server/src/main/java/com/vaadin/server/SerializableFunction.java create mode 100644 server/src/main/java/com/vaadin/server/SerializablePredicate.java diff --git a/server/src/main/java/com/vaadin/data/BeanBinder.java b/server/src/main/java/com/vaadin/data/BeanBinder.java index 96654e37a0..a57082357f 100644 --- a/server/src/main/java/com/vaadin/data/BeanBinder.java +++ b/server/src/main/java/com/vaadin/data/BeanBinder.java @@ -21,12 +21,13 @@ import java.beans.PropertyDescriptor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Objects; -import java.util.function.Function; -import java.util.function.Predicate; import com.vaadin.data.util.BeanUtil; import com.vaadin.data.util.converter.Converter; import com.vaadin.data.validator.BeanValidator; +import com.vaadin.server.SerializableBiConsumer; +import com.vaadin.server.SerializableFunction; +import com.vaadin.server.SerializablePredicate; import com.vaadin.util.ReflectTools; /** @@ -63,7 +64,8 @@ public class BeanBinder extends Binder { @Override public default BeanBinding withValidator( - Predicate predicate, String message) { + SerializablePredicate predicate, + String message) { return (BeanBinding) Binding.super.withValidator( predicate, message); } @@ -74,16 +76,16 @@ public class BeanBinder extends Binder { @Override public default BeanBinding withConverter( - Function toModel, - Function toPresentation) { + SerializableFunction toModel, + SerializableFunction toPresentation) { return (BeanBinding) Binding.super.withConverter( toModel, toPresentation); } @Override public default BeanBinding withConverter( - Function toModel, - Function toPresentation, + SerializableFunction toModel, + SerializableFunction toPresentation, String errorMessage) { return (BeanBinding) Binding.super.withConverter( toModel, toPresentation, errorMessage); @@ -110,7 +112,7 @@ public class BeanBinder extends Binder { * @throws IllegalArgumentException * if the property has no accessible getter * - * @see Binding#bind(Function, java.util.function.BiConsumer) + * @see Binding#bind(SerializableFunction, SerializableBiConsumer) */ public void bind(String propertyName); } @@ -294,8 +296,7 @@ public class BeanBinder extends Binder { * @throws IllegalArgumentException * if the property has no accessible getter * - * @see #bind(HasValue, java.util.function.Function, - * java.util.function.BiConsumer) + * @see #bind(HasValue, SerializableFunction, SerializableBiConsumer) */ public void bind(HasValue field, String propertyName) { diff --git a/server/src/main/java/com/vaadin/data/Binder.java b/server/src/main/java/com/vaadin/data/Binder.java index 5493712cec..d3c2befefb 100644 --- a/server/src/main/java/com/vaadin/data/Binder.java +++ b/server/src/main/java/com/vaadin/data/Binder.java @@ -28,8 +28,6 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.function.BiConsumer; -import java.util.function.Function; -import java.util.function.Predicate; import java.util.stream.Collectors; import com.vaadin.data.util.converter.Converter; @@ -37,6 +35,9 @@ import com.vaadin.data.util.converter.StringToIntegerConverter; import com.vaadin.data.util.converter.ValueContext; import com.vaadin.event.EventRouter; import com.vaadin.server.ErrorMessage; +import com.vaadin.server.SerializableBiConsumer; +import com.vaadin.server.SerializableFunction; +import com.vaadin.server.SerializablePredicate; import com.vaadin.server.UserError; import com.vaadin.shared.Registration; import com.vaadin.ui.AbstractComponent; @@ -139,8 +140,8 @@ public class Binder implements Serializable { * @throws IllegalStateException * if {@code bind} has already been called on this binding */ - public void bind(Function getter, - BiConsumer setter); + public void bind(SerializableFunction getter, + com.vaadin.server.SerializableBiConsumer setter); /** * Adds a validator to this binding. Validators are applied, in @@ -159,14 +160,14 @@ public class Binder implements Serializable { /** * A convenience method to add a validator to this binding using the - * {@link Validator#from(Predicate, String)} factory method. + * {@link Validator#from(SerializablePredicate, String)} factory method. *

* Validators are applied, in registration order, when the field value * is saved to the backing property. If any validator returns a failure, * the property value is not updated. * * @see #withValidator(Validator) - * @see Validator#from(Predicate, String) + * @see Validator#from(SerializablePredicate, String) * * @param predicate * the predicate performing validation, not null @@ -177,7 +178,8 @@ public class Binder implements Serializable { * if {@code bind} has already been called */ public default Binding withValidator( - Predicate predicate, String message) { + SerializablePredicate predicate, + String message) { return withValidator(Validator.from(predicate, message)); } @@ -189,8 +191,8 @@ public class Binder implements Serializable { * which must match the current target data type of the binding, and a * model type, which can be any data type and becomes the new target * type of the binding. When invoking - * {@link #bind(Function, BiConsumer)}, the target type of the binding - * must match the getter/setter types. + * {@link #bind(SerializableFunction, SerializableBiConsumer)}, the + * target type of the binding must match the getter/setter types. *

* For instance, a {@code TextField} can be bound to an integer-typed * property using an appropriate converter such as a @@ -215,8 +217,8 @@ public class Binder implements Serializable { * type, which must match the current target data type of the binding, * and a model type, which can be any data type and becomes the new * target type of the binding. When invoking - * {@link #bind(Function, BiConsumer)}, the target type of the binding - * must match the getter/setter types. + * {@link #bind(SerializableFunction, SerializableBiConsumer)}, the + * target type of the binding must match the getter/setter types. *

* For instance, a {@code TextField} can be bound to an integer-typed * property using appropriate functions such as: @@ -235,8 +237,8 @@ public class Binder implements Serializable { * if {@code bind} has already been called */ public default Binding withConverter( - Function toModel, - Function toPresentation) { + SerializableFunction toModel, + SerializableFunction toPresentation) { return withConverter(Converter.from(toModel, toPresentation, exception -> exception.getMessage())); } @@ -250,8 +252,8 @@ public class Binder implements Serializable { * type, which must match the current target data type of the binding, * and a model type, which can be any data type and becomes the new * target type of the binding. When invoking - * {@link #bind(Function, BiConsumer)}, the target type of the binding - * must match the getter/setter types. + * {@link #bind(SerializableFunction, SerializableBiConsumer)}, the + * target type of the binding must match the getter/setter types. *

* For instance, a {@code TextField} can be bound to an integer-typed * property using appropriate functions such as: @@ -273,8 +275,8 @@ public class Binder implements Serializable { * if {@code bind} has already been called */ public default Binding withConverter( - Function toModel, - Function toPresentation, + SerializableFunction toModel, + SerializableFunction toPresentation, String errorMessage) { return withConverter(Converter.from(toModel, toPresentation, exception -> errorMessage)); @@ -411,8 +413,8 @@ public class Binder implements Serializable { private ValidationStatusHandler statusHandler; private boolean isStatusHandlerChanged; - private Function getter; - private BiConsumer setter; + private SerializableFunction getter; + private SerializableBiConsumer setter; /** * Contains all converters and validators chained together in the @@ -443,8 +445,8 @@ public class Binder implements Serializable { } @Override - public void bind(Function getter, - BiConsumer setter) { + public void bind(SerializableFunction getter, + SerializableBiConsumer setter) { checkUnbound(); Objects.requireNonNull(getter, "getter cannot be null"); @@ -717,7 +719,7 @@ public class Binder implements Serializable { /** * Creates a new binding for the given field. The returned binding may be - * further configured before invoking + * further configured before invoking <<<<<<< Upstream, based on master * {@link Binding#bind(Function, BiConsumer) Binding.bind} which completes * the binding. Until {@code Binding.bind} is called, the binding has no * effect. @@ -727,7 +729,11 @@ public class Binder implements Serializable { * automatically change {@code null} to a null representation provided by * {@link HasValue#getEmptyValue()}. This conversion is one-way only, if you * want to have a two-way mapping back to {@code null}, use - * {@link Binding#withNullRepresentation(Object))}. + * {@link Binding#withNullRepresentation(Object))}. ======= + * {@link Binding#bind(SerializableFunction, SerializableBiConsumer) + * Binding.bind} which completes the binding. Until {@code Binding.bind} is + * called, the binding has no effect. >>>>>>> 7d541b5 Correct serializable + * issues and test that components can be serialized * * @param * the value type of the field @@ -735,7 +741,7 @@ public class Binder implements Serializable { * the field to be bound, not null * @return the new binding * - * @see #bind(HasValue, Function, BiConsumer) + * @see #bind(HasValue, SerializableFunction, SerializableBiConsumer) */ public Binding forField( HasValue field) { @@ -803,8 +809,8 @@ public class Binder implements Serializable { * if read-only */ public void bind(HasValue field, - Function getter, - BiConsumer setter) { + SerializableFunction getter, + SerializableBiConsumer setter) { forField(field).bind(getter, setter); } @@ -1151,7 +1157,8 @@ public class Binder implements Serializable { *

  • {@link #load(Object)} is called *
  • {@link #bind(Object)} is called *
  • {@link #unbind(Object)} is called - *
  • {@link Binding#bind(Function, BiConsumer)} is called + *
  • {@link Binding#bind(SerializableFunction, SerializableBiConsumer)} is + * called *
  • {@link Binder#validate()} or {@link Binding#validate()} is called * * diff --git a/server/src/main/java/com/vaadin/data/Validator.java b/server/src/main/java/com/vaadin/data/Validator.java index 5eda581284..4d4a19fbe8 100644 --- a/server/src/main/java/com/vaadin/data/Validator.java +++ b/server/src/main/java/com/vaadin/data/Validator.java @@ -21,6 +21,8 @@ import java.util.Objects; import java.util.function.Function; import java.util.function.Predicate; +import com.vaadin.server.SerializablePredicate; + /** * A functional interface for validating user input or other potentially invalid * data. When a validator instance is applied to a value of the corresponding @@ -117,7 +119,7 @@ public interface Validator extends Function>, Serializable { * the message returned if validation fails, not null * @return the new validator using the function */ - public static Validator from(Predicate guard, + public static Validator from(SerializablePredicate guard, String errorMessage) { Objects.requireNonNull(guard, "guard cannot be null"); Objects.requireNonNull(errorMessage, "errorMessage cannot be null"); diff --git a/server/src/main/java/com/vaadin/data/util/converter/Converter.java b/server/src/main/java/com/vaadin/data/util/converter/Converter.java index c25c567773..3521789e5a 100644 --- a/server/src/main/java/com/vaadin/data/util/converter/Converter.java +++ b/server/src/main/java/com/vaadin/data/util/converter/Converter.java @@ -22,6 +22,7 @@ import java.util.function.Function; import com.vaadin.data.Binder.Binding; import com.vaadin.data.Result; +import com.vaadin.server.SerializableFunction; /** * Interface that implements conversion between a model and a presentation type. @@ -108,9 +109,10 @@ public interface Converter extends Serializable { * @see Result * @see Function */ - public static Converter from(Function toModel, - Function toPresentation, - Function onError) { + public static Converter from( + SerializableFunction toModel, + SerializableFunction toPresentation, + SerializableFunction onError) { return from(val -> Result.of(() -> toModel.apply(val), onError), toPresentation); @@ -131,8 +133,9 @@ public interface Converter extends Serializable { * * @see Function */ - public static Converter from(Function> toModel, - Function toPresentation) { + public static Converter from( + SerializableFunction> toModel, + SerializableFunction toPresentation) { return new Converter() { @Override diff --git a/server/src/main/java/com/vaadin/data/validator/AbstractValidator.java b/server/src/main/java/com/vaadin/data/validator/AbstractValidator.java index ea390ae7f7..b798d2bf73 100644 --- a/server/src/main/java/com/vaadin/data/validator/AbstractValidator.java +++ b/server/src/main/java/com/vaadin/data/validator/AbstractValidator.java @@ -16,10 +16,10 @@ package com.vaadin.data.validator; import java.util.Objects; -import java.util.function.Function; import com.vaadin.data.Result; import com.vaadin.data.Validator; +import com.vaadin.server.SerializableFunction; /** * An abstract base class for typed validators. @@ -31,7 +31,7 @@ import com.vaadin.data.Validator; */ public abstract class AbstractValidator implements Validator { - private Function messageProvider; + private SerializableFunction messageProvider; /** * Constructs a validator with the given error message. The substring "{0}" diff --git a/server/src/main/java/com/vaadin/server/SerializableBiConsumer.java b/server/src/main/java/com/vaadin/server/SerializableBiConsumer.java new file mode 100644 index 0000000000..bdf83dd9ba --- /dev/null +++ b/server/src/main/java/com/vaadin/server/SerializableBiConsumer.java @@ -0,0 +1,38 @@ +/* + * Copyright 2000-2016 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.server; + +import java.io.Serializable; +import java.util.function.BiConsumer; + +/** + * A {@link BiConsumer} that is also {@link Serializable}. + * + * @see {@link BiConsumer} + * @param + * the type of the first argument to the operation + * @param + * the type of the second argument to the operation + * + * @since 8.0 + * @author Vaadin Ltd + * + */ +@FunctionalInterface +public interface SerializableBiConsumer + extends BiConsumer, Serializable { + // Only method inherited from BiConsumer +} diff --git a/server/src/main/java/com/vaadin/server/SerializableComparator.java b/server/src/main/java/com/vaadin/server/SerializableComparator.java new file mode 100644 index 0000000000..213cc5cc49 --- /dev/null +++ b/server/src/main/java/com/vaadin/server/SerializableComparator.java @@ -0,0 +1,49 @@ +/* + * Copyright 2000-2016 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.server; + +import java.io.Serializable; +import java.util.Comparator; + +/** + * A {@link Comparator} that is also {@link Serializable}. + * + * @author Vaadin Ltd + * @param + * the type of objects that may be compared by this comparator + * @since 8.0 + * + */ +@FunctionalInterface +public interface SerializableComparator extends Comparator, Serializable { + + /** + * Returns a {@link SerializableComparator} instance which delegates its + * logic to the provided {@code comparator}. + * + * @param comparator + * comparator to convert + * @param + * the type of objects that may be compared by this comparator + * @param + * the comparator type + * @return a SerializableComparator view of the {@code comparator} + */ + static & Serializable, T> SerializableComparator asInstance( + C comparator) { + return (arg1, arg2) -> comparator.compare(arg1, arg2); + } +} diff --git a/server/src/main/java/com/vaadin/server/SerializableFunction.java b/server/src/main/java/com/vaadin/server/SerializableFunction.java new file mode 100644 index 0000000000..330be5f72a --- /dev/null +++ b/server/src/main/java/com/vaadin/server/SerializableFunction.java @@ -0,0 +1,46 @@ +/* + * Copyright 2000-2016 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.server; + +import java.io.Serializable; +import java.util.function.Function; + +/** + * A {@link Function} that is also {@link Serializable}. + * + * @see Function + * @author Vaadin Ltd + * @since 8.0 + * @param + * the type of the input to the function + * @param + * the type of the result of the function + */ +@FunctionalInterface +public interface SerializableFunction + extends Function, Serializable { + /** + * Returns a function that always returns its input argument. + * + * @param + * the type of the input and output objects to the function + * @return a function that always returns its input argument + */ + static SerializableFunction identity() { + return t -> t; + } + +} diff --git a/server/src/main/java/com/vaadin/server/SerializablePredicate.java b/server/src/main/java/com/vaadin/server/SerializablePredicate.java new file mode 100644 index 0000000000..5172aebe70 --- /dev/null +++ b/server/src/main/java/com/vaadin/server/SerializablePredicate.java @@ -0,0 +1,32 @@ +/* + * Copyright 2000-2016 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.server; + +import java.io.Serializable; +import java.util.function.Predicate; + +/** + * A {@link Predicate} that is also {@link Serializable}. + * + * @author Vaadin Ltd + * @since 8.0 + * @param + * the type of the input to the predicate + * + */ +public interface SerializablePredicate extends Predicate, Serializable { + // Only method inherited from Function +} diff --git a/server/src/main/java/com/vaadin/server/data/BackEndDataSource.java b/server/src/main/java/com/vaadin/server/data/BackEndDataSource.java index c792ebd23e..2eedeb6839 100644 --- a/server/src/main/java/com/vaadin/server/data/BackEndDataSource.java +++ b/server/src/main/java/com/vaadin/server/data/BackEndDataSource.java @@ -18,9 +18,10 @@ package com.vaadin.server.data; import java.util.ArrayList; import java.util.List; import java.util.Objects; -import java.util.function.Function; import java.util.stream.Stream; +import com.vaadin.server.SerializableFunction; + /** * A {@link DataSource} for any back end. * @@ -29,8 +30,8 @@ import java.util.stream.Stream; */ public class BackEndDataSource extends AbstractDataSource { - private Function> request; - private Function sizeCallback; + private SerializableFunction> request; + private SerializableFunction sizeCallback; /** * Constructs a new DataSource to request data from an arbitrary back end @@ -41,8 +42,8 @@ public class BackEndDataSource extends AbstractDataSource { * @param sizeCallback * function that return the amount of data in back end for query */ - public BackEndDataSource(Function> request, - Function sizeCallback) { + public BackEndDataSource(SerializableFunction> request, + SerializableFunction sizeCallback) { Objects.requireNonNull(request, "Request function can't be null"); Objects.requireNonNull(sizeCallback, "Size callback can't be null"); this.request = request; diff --git a/server/src/main/java/com/vaadin/server/data/DataCommunicator.java b/server/src/main/java/com/vaadin/server/data/DataCommunicator.java index 8238777c64..a0ce859892 100644 --- a/server/src/main/java/com/vaadin/server/data/DataCommunicator.java +++ b/server/src/main/java/com/vaadin/server/data/DataCommunicator.java @@ -31,6 +31,7 @@ import java.util.stream.Stream; import com.vaadin.server.AbstractExtension; import com.vaadin.server.KeyMapper; +import com.vaadin.server.SerializablePredicate; import com.vaadin.shared.Range; import com.vaadin.shared.Registration; import com.vaadin.shared.data.DataCommunicatorClientRpc; @@ -187,7 +188,7 @@ public class DataCommunicator extends AbstractExtension { private Range pushRows = Range.withLength(0, 40); private Comparator inMemorySorting; - private Predicate inMemoryFilter; + private SerializablePredicate inMemoryFilter; private List> backEndSorting = new ArrayList<>(); private DataCommunicatorClientRpc rpc; @@ -406,7 +407,7 @@ public class DataCommunicator extends AbstractExtension { * @param predicate * predicate used to filter data */ - public void setInMemoryFilter(Predicate predicate) { + public void setInMemoryFilter(SerializablePredicate predicate) { inMemoryFilter = predicate; reset(); } diff --git a/server/src/main/java/com/vaadin/ui/AbstractMultiSelect.java b/server/src/main/java/com/vaadin/ui/AbstractMultiSelect.java index 7332941f91..0ac647e3af 100644 --- a/server/src/main/java/com/vaadin/ui/AbstractMultiSelect.java +++ b/server/src/main/java/com/vaadin/ui/AbstractMultiSelect.java @@ -30,6 +30,7 @@ import com.vaadin.event.selection.MultiSelectionEvent; import com.vaadin.event.selection.MultiSelectionListener; import com.vaadin.server.Resource; import com.vaadin.server.ResourceReference; +import com.vaadin.server.SerializablePredicate; import com.vaadin.server.data.DataGenerator; import com.vaadin.shared.Registration; import com.vaadin.shared.data.selection.MultiSelectServerRpc; @@ -279,7 +280,7 @@ public abstract class AbstractMultiSelect * The item enabled status provider. It is up to the implementing class to * support this or not. */ - private Predicate itemEnabledProvider = item -> true; + private SerializablePredicate itemEnabledProvider = item -> true; /** * Creates a new multi select with an empty data source. @@ -440,14 +441,14 @@ public abstract class AbstractMultiSelect * Returns the item enabled provider for this multiselect. *

    * Implementation note: Override this method and - * {@link #setItemEnabledProvider(Predicate)} as {@code public} and invoke - * {@code super} methods to support this feature in the multiselect - * component. + * {@link #setItemEnabledProvider(SerializablePredicate)} as {@code public} + * and invoke {@code super} methods to support this feature in the + * multiselect component. * * @return the item enabled provider, not {@code null} * @see #setItemEnabledProvider(Predicate) */ - protected Predicate getItemEnabledProvider() { + protected SerializablePredicate getItemEnabledProvider() { return itemEnabledProvider; } @@ -466,7 +467,8 @@ public abstract class AbstractMultiSelect * @param itemEnabledProvider * the item enabled provider to set, not {@code null} */ - protected void setItemEnabledProvider(Predicate itemEnabledProvider) { + protected void setItemEnabledProvider( + SerializablePredicate itemEnabledProvider) { Objects.requireNonNull(itemEnabledProvider); this.itemEnabledProvider = itemEnabledProvider; } diff --git a/server/src/main/java/com/vaadin/ui/CheckBoxGroup.java b/server/src/main/java/com/vaadin/ui/CheckBoxGroup.java index 0a1e4c71af..c088949899 100644 --- a/server/src/main/java/com/vaadin/ui/CheckBoxGroup.java +++ b/server/src/main/java/com/vaadin/ui/CheckBoxGroup.java @@ -17,9 +17,9 @@ package com.vaadin.ui; import java.util.Collection; -import java.util.function.Predicate; import com.vaadin.data.Listing; +import com.vaadin.server.SerializablePredicate; import com.vaadin.server.data.DataSource; import com.vaadin.shared.ui.optiongroup.CheckBoxGroupState; @@ -128,12 +128,13 @@ public class CheckBoxGroup extends AbstractMultiSelect { } @Override - public Predicate getItemEnabledProvider() { + public SerializablePredicate getItemEnabledProvider() { return super.getItemEnabledProvider(); } @Override - public void setItemEnabledProvider(Predicate itemEnabledProvider) { + public void setItemEnabledProvider( + SerializablePredicate itemEnabledProvider) { super.setItemEnabledProvider(itemEnabledProvider); } } diff --git a/server/src/main/java/com/vaadin/ui/Grid.java b/server/src/main/java/com/vaadin/ui/Grid.java index b904565a64..db85ec1fb2 100644 --- a/server/src/main/java/com/vaadin/ui/Grid.java +++ b/server/src/main/java/com/vaadin/ui/Grid.java @@ -32,6 +32,7 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.function.BinaryOperator; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -41,6 +42,8 @@ import com.vaadin.event.ContextClickEvent; import com.vaadin.event.EventListener; import com.vaadin.server.EncodeResult; import com.vaadin.server.JsonCodec; +import com.vaadin.server.SerializableComparator; +import com.vaadin.server.SerializableFunction; import com.vaadin.server.data.SortOrder; import com.vaadin.shared.MouseEventDetails; import com.vaadin.shared.Registration; @@ -461,7 +464,7 @@ public class Grid extends AbstractSingleSelect implements HasComponents { */ @FunctionalInterface public interface DescriptionGenerator - extends Function, Serializable { + extends SerializableFunction { } /** @@ -539,10 +542,14 @@ public class Grid extends AbstractSingleSelect implements HasComponents { // Set sort orders // In-memory comparator - Comparator comparator = sortOrder.stream() + BinaryOperator> operator = (comparator1, + comparator2) -> SerializableComparator.asInstance( + (Comparator & Serializable) comparator1 + .thenComparing(comparator2)); + SerializableComparator comparator = sortOrder.stream() .map(order -> order.getSorted() .getComparator(order.getDirection())) - .reduce((x, y) -> 0, Comparator::thenComparing); + .reduce((x, y) -> 0, operator); getDataCommunicator().setInMemorySorting(comparator); // Back-end sort properties @@ -755,10 +762,10 @@ public class Grid extends AbstractSingleSelect implements HasComponents { */ public static class Column extends AbstractGridExtension { - private final Function valueProvider; + private final SerializableFunction valueProvider; - private Function>> sortOrderProvider; - private Comparator comparator; + private SerializableFunction>> sortOrderProvider; + private SerializableComparator comparator; private StyleGenerator styleGenerator = item -> null; private DescriptionGenerator descriptionGenerator; @@ -773,7 +780,8 @@ public class Grid extends AbstractSingleSelect implements HasComponents { * @param renderer * the type of value */ - protected Column(String caption, Function valueProvider, + protected Column(String caption, + SerializableFunction valueProvider, Renderer renderer) { Objects.requireNonNull(caption, "Header caption can't be null"); Objects.requireNonNull(valueProvider, @@ -995,7 +1003,8 @@ public class Grid extends AbstractSingleSelect implements HasComponents { * the comparator to use when sorting data in this column * @return this column */ - public Column setComparator(Comparator comparator) { + public Column setComparator( + SerializableComparator comparator) { Objects.requireNonNull(comparator, "Comparator can't be null"); this.comparator = comparator; return this; @@ -1009,11 +1018,13 @@ public class Grid extends AbstractSingleSelect implements HasComponents { * the direction this column is sorted by * @return comparator for this column */ - public Comparator getComparator(SortDirection sortDirection) { + public SerializableComparator getComparator( + SortDirection sortDirection) { Objects.requireNonNull(comparator, "No comparator defined for sorted column."); boolean reverse = sortDirection != SortDirection.ASCENDING; - return reverse ? comparator.reversed() : comparator; + return reverse ? (t1, t2) -> comparator.reversed().compare(t1, t2) + : comparator; } /** @@ -1044,7 +1055,7 @@ public class Grid extends AbstractSingleSelect implements HasComponents { * @return this column */ public Column setSortOrderProvider( - Function>> provider) { + SerializableFunction>> provider) { Objects.requireNonNull(provider, "Sort order provider can't be null"); sortOrderProvider = provider; @@ -1708,7 +1719,7 @@ public class Grid extends AbstractSingleSelect implements HasComponents { * @see {@link AbstractRenderer} */ public Column addColumn(String identifier, - Function valueProvider, + SerializableFunction valueProvider, AbstractRenderer renderer) throws IllegalArgumentException { if (columnKeys.containsKey(identifier)) { @@ -1737,7 +1748,7 @@ public class Grid extends AbstractSingleSelect implements HasComponents { * if the same identifier is used for multiple columns */ public Column addColumn(String identifier, - Function valueProvider) { + SerializableFunction valueProvider) { return addColumn(identifier, valueProvider, new TextRenderer()); } @@ -1751,7 +1762,8 @@ public class Grid extends AbstractSingleSelect implements HasComponents { * * @return the new column */ - public Column addColumn(Function valueProvider) { + public Column addColumn( + SerializableFunction valueProvider) { return addColumn(getGeneratedIdentifier(), valueProvider, new TextRenderer()); } @@ -1771,7 +1783,8 @@ public class Grid extends AbstractSingleSelect implements HasComponents { * * @see {@link AbstractRenderer} */ - public Column addColumn(Function valueProvider, + public Column addColumn( + SerializableFunction valueProvider, AbstractRenderer renderer) { return addColumn(getGeneratedIdentifier(), valueProvider, renderer); } @@ -2522,4 +2535,5 @@ public class Grid extends AbstractSingleSelect implements HasComponents { boolean userOriginated) { fireEvent(new ColumnResizeEvent(this, column, userOriginated)); } + } diff --git a/server/src/main/java/com/vaadin/ui/IconGenerator.java b/server/src/main/java/com/vaadin/ui/IconGenerator.java index 41f11dad81..50da1c5303 100644 --- a/server/src/main/java/com/vaadin/ui/IconGenerator.java +++ b/server/src/main/java/com/vaadin/ui/IconGenerator.java @@ -15,10 +15,8 @@ */ package com.vaadin.ui; -import java.io.Serializable; -import java.util.function.Function; - import com.vaadin.server.Resource; +import com.vaadin.server.SerializableFunction; /** * A callback interface for generating icons for an item. @@ -27,7 +25,7 @@ import com.vaadin.server.Resource; * item type for which the icon is generated */ @FunctionalInterface -public interface IconGenerator extends Function, Serializable { +public interface IconGenerator extends SerializableFunction { /** * Gets an icon resource for the {@code item}. diff --git a/server/src/main/java/com/vaadin/ui/ItemCaptionGenerator.java b/server/src/main/java/com/vaadin/ui/ItemCaptionGenerator.java index dc699c077b..0a57d901e9 100644 --- a/server/src/main/java/com/vaadin/ui/ItemCaptionGenerator.java +++ b/server/src/main/java/com/vaadin/ui/ItemCaptionGenerator.java @@ -15,8 +15,7 @@ */ package com.vaadin.ui; -import java.io.Serializable; -import java.util.function.Function; +import com.vaadin.server.SerializableFunction; /** * {@link ItemCaptionGenerator} can be used to customize the string shown to the @@ -30,7 +29,7 @@ import java.util.function.Function; */ @FunctionalInterface public interface ItemCaptionGenerator - extends Function, Serializable { + extends SerializableFunction { /** * Gets a caption for the {@code item}. diff --git a/server/src/main/java/com/vaadin/ui/RadioButtonGroup.java b/server/src/main/java/com/vaadin/ui/RadioButtonGroup.java index 13aa840462..a1474c91d4 100644 --- a/server/src/main/java/com/vaadin/ui/RadioButtonGroup.java +++ b/server/src/main/java/com/vaadin/ui/RadioButtonGroup.java @@ -18,11 +18,11 @@ package com.vaadin.ui; import java.util.Collection; import java.util.Objects; -import java.util.function.Predicate; import com.vaadin.data.Listing; import com.vaadin.server.Resource; import com.vaadin.server.ResourceReference; +import com.vaadin.server.SerializablePredicate; import com.vaadin.server.data.DataGenerator; import com.vaadin.server.data.DataSource; import com.vaadin.shared.ui.ListingJsonConstants; @@ -45,7 +45,7 @@ public class RadioButtonGroup extends AbstractSingleSelect { private ItemCaptionGenerator itemCaptionGenerator = String::valueOf; - private Predicate itemEnabledProvider = item -> true; + private SerializablePredicate itemEnabledProvider = item -> true; /** * Constructs a new RadioButtonGroup with caption. @@ -226,7 +226,7 @@ public class RadioButtonGroup extends AbstractSingleSelect { * @return the item enabled predicate * @see #setItemEnabledProvider */ - public Predicate getItemEnabledProvider() { + public SerializablePredicate getItemEnabledProvider() { return itemEnabledProvider; } @@ -240,7 +240,8 @@ public class RadioButtonGroup extends AbstractSingleSelect { * @param itemEnabledProvider * the item enable predicate, not null */ - public void setItemEnabledProvider(Predicate itemEnabledProvider) { + public void setItemEnabledProvider( + SerializablePredicate itemEnabledProvider) { Objects.requireNonNull(itemEnabledProvider); this.itemEnabledProvider = itemEnabledProvider; } diff --git a/server/src/main/java/com/vaadin/ui/StyleGenerator.java b/server/src/main/java/com/vaadin/ui/StyleGenerator.java index ddec2a2071..496d8a118a 100644 --- a/server/src/main/java/com/vaadin/ui/StyleGenerator.java +++ b/server/src/main/java/com/vaadin/ui/StyleGenerator.java @@ -15,8 +15,7 @@ */ package com.vaadin.ui; -import java.io.Serializable; -import java.util.function.Function; +import com.vaadin.server.SerializableFunction; /** * A callback interface for generating custom CSS class names for items. @@ -28,7 +27,7 @@ import java.util.function.Function; * @author Vaadin Ltd */ @FunctionalInterface -public interface StyleGenerator extends Function, Serializable { +public interface StyleGenerator extends SerializableFunction { /** * Gets a class name for the {@code item}. diff --git a/server/src/test/java/com/vaadin/data/BinderConverterValidatorTest.java b/server/src/test/java/com/vaadin/data/BinderConverterValidatorTest.java index 73443155c7..1ce373bf47 100644 --- a/server/src/test/java/com/vaadin/data/BinderConverterValidatorTest.java +++ b/server/src/test/java/com/vaadin/data/BinderConverterValidatorTest.java @@ -23,7 +23,6 @@ import static org.junit.Assert.assertTrue; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Predicate; import org.junit.Assert; import org.junit.Before; @@ -34,6 +33,7 @@ import com.vaadin.data.util.converter.StringToIntegerConverter; import com.vaadin.data.validator.NotEmptyValidator; import com.vaadin.server.AbstractErrorMessage; import com.vaadin.server.ErrorMessage; +import com.vaadin.server.SerializablePredicate; import com.vaadin.server.UserError; import com.vaadin.tests.data.bean.Person; import com.vaadin.ui.Label; @@ -640,7 +640,8 @@ public class BinderConverterValidatorTest @Test public void binderLoad_withCrossFieldValidation_clearsErrors() { TextField lastNameField = new TextField(); - final Predicate lengthPredicate = v -> v.length() > 2; + final SerializablePredicate lengthPredicate = v -> v + .length() > 2; Binding firstNameBinding = binder .forField(nameField).withValidator(lengthPredicate, "length"); diff --git a/server/src/test/java/com/vaadin/tests/data/converter/ConverterTest.java b/server/src/test/java/com/vaadin/tests/data/converter/ConverterTest.java index 95f200bdf6..6d653bb932 100644 --- a/server/src/test/java/com/vaadin/tests/data/converter/ConverterTest.java +++ b/server/src/test/java/com/vaadin/tests/data/converter/ConverterTest.java @@ -1,17 +1,16 @@ package com.vaadin.tests.data.converter; -import java.util.function.Function; - import org.junit.Assert; import org.junit.Test; import com.vaadin.data.Result; import com.vaadin.data.util.converter.Converter; import com.vaadin.data.util.converter.ValueContext; +import com.vaadin.server.SerializableFunction; public class ConverterTest { - Function> toModel = presentation -> { + SerializableFunction> toModel = presentation -> { if (presentation.startsWith("presentation-")) { return Result.ok(presentation.substring("presentation-".length())); } else { @@ -19,7 +18,8 @@ public class ConverterTest { } }; - Function toPresentation = model -> "presentation-" + model; + SerializableFunction toPresentation = model -> "presentation-" + + model; Converter converter = Converter.from(toModel, toPresentation); diff --git a/server/src/test/java/com/vaadin/tests/server/ClassesSerializableTest.java b/server/src/test/java/com/vaadin/tests/server/ClassesSerializableTest.java index ea002f37f6..0a1629c2f9 100644 --- a/server/src/test/java/com/vaadin/tests/server/ClassesSerializableTest.java +++ b/server/src/test/java/com/vaadin/tests/server/ClassesSerializableTest.java @@ -1,9 +1,18 @@ package com.vaadin.tests.server; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.io.Serializable; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -11,12 +20,17 @@ import java.util.Comparator; import java.util.Enumeration; import java.util.Iterator; import java.util.List; +import java.util.Optional; import java.util.jar.JarEntry; import java.util.jar.JarFile; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.junit.Assert; import org.junit.Test; +import com.vaadin.ui.Component; + public class ClassesSerializableTest { /** @@ -99,16 +113,30 @@ public class ClassesSerializableTest { classes.addAll(findServerClasses(location)); } + ArrayList nonSerializableFunctionFields = new ArrayList<>(); + ArrayList> nonSerializableClasses = new ArrayList<>(); for (String className : classes) { Class cls = Class.forName(className); + // Don't add classes that have a @Ignore annotation on the class + if (isTestClass(cls)) { + continue; + } + + // report fields that use lambda types that won't be serializable + // (also in syntehtic classes) + Stream.of(cls.getDeclaredFields()) + .filter(field -> isFunctionalType(field.getGenericType())) + .forEach(nonSerializableFunctionFields::add); + // skip annotations and synthetic classes if (cls.isAnnotation() || cls.isSynthetic()) { continue; } - // Don't add classes that have a @Ignore annotation on the class - if (isTestClass(cls)) { - continue; + + if (Component.class.isAssignableFrom(cls) && !cls.isInterface() + && !Modifier.isAbstract(cls.getModifiers())) { + serializeAndDeserialize(cls); } // report non-serializable classes and interfaces @@ -135,26 +163,71 @@ public class ClassesSerializableTest { // useful failure message including all non-serializable classes and // interfaces if (!nonSerializableClasses.isEmpty()) { - String nonSerializableString = ""; - Iterator> it = nonSerializableClasses.iterator(); - while (it.hasNext()) { - Class c = it.next(); - nonSerializableString += ", " + c.getName(); - if (c.isAnonymousClass()) { - nonSerializableString += "(super: "; - nonSerializableString += c.getSuperclass().getName(); - nonSerializableString += ", interfaces: "; - for (Class i : c.getInterfaces()) { - nonSerializableString += i.getName(); - nonSerializableString += ","; - } - nonSerializableString += ")"; + failSerializableClasses(nonSerializableClasses); + } + + if (!nonSerializableFunctionFields.isEmpty()) { + failSerializableFields(nonSerializableFunctionFields); + } + } + + private void serializeAndDeserialize(Class clazz) + throws IOException, ClassNotFoundException, InstantiationException, + IllegalAccessException, IllegalArgumentException, + InvocationTargetException { + Optional> defaultCtor = Stream + .of(clazz.getDeclaredConstructors()) + .filter(ctor -> ctor.getParameterCount() == 0).findFirst(); + if (!defaultCtor.isPresent()) { + return; + } + defaultCtor.get().setAccessible(true); + Object instance = defaultCtor.get().newInstance(); + ByteArrayOutputStream bs = new ByteArrayOutputStream(); + ObjectOutputStream out = new ObjectOutputStream(bs); + out.writeObject(instance); + byte[] data = bs.toByteArray(); + ObjectInputStream in = new ObjectInputStream( + new ByteArrayInputStream(data)); + in.readObject(); + } + + private void failSerializableFields( + ArrayList nonSerializableFunctionFields) { + String nonSerializableString = nonSerializableFunctionFields.stream() + .map(field -> String.format("%s.%s", + field.getDeclaringClass().getName(), field.getName())) + .collect(Collectors.joining(", ")); + + Assert.fail("Fields with functional types that are not serializable: " + + nonSerializableString); + } + + private void failSerializableClasses( + ArrayList> nonSerializableClasses) { + String nonSerializableString = ""; + Iterator> it = nonSerializableClasses.iterator(); + while (it.hasNext()) { + Class c = it.next(); + nonSerializableString += ", " + c.getName(); + if (c.isAnonymousClass()) { + nonSerializableString += "(super: "; + nonSerializableString += c.getSuperclass().getName(); + nonSerializableString += ", interfaces: "; + for (Class i : c.getInterfaces()) { + nonSerializableString += i.getName(); + nonSerializableString += ","; } + nonSerializableString += ")"; } - Assert.fail( - "Serializable not implemented by the following classes and interfaces: " - + nonSerializableString); } + Assert.fail( + "Serializable not implemented by the following classes and interfaces: " + + nonSerializableString); + } + + private static boolean isFunctionalType(Type type) { + return type.getTypeName().contains("java.util.function"); } private boolean isTestClass(Class cls) { @@ -181,7 +254,6 @@ public class ClassesSerializableTest { * * @return List of class path segment strings */ - // private final static List getRawClasspathEntries() { // try to keep the order of the classpath List locations = new ArrayList<>(); diff --git a/server/src/test/java/com/vaadin/tests/server/component/grid/GridDefaultHeaderTest.java b/server/src/test/java/com/vaadin/tests/server/component/grid/GridDefaultHeaderTest.java index 80984cc647..0d677a8f04 100644 --- a/server/src/test/java/com/vaadin/tests/server/component/grid/GridDefaultHeaderTest.java +++ b/server/src/test/java/com/vaadin/tests/server/component/grid/GridDefaultHeaderTest.java @@ -19,11 +19,10 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; -import java.util.function.Function; - import org.junit.Before; import org.junit.Test; +import com.vaadin.server.SerializableFunction; import com.vaadin.ui.Grid; import com.vaadin.ui.Grid.Column; import com.vaadin.ui.Grid.HeaderRow; @@ -36,8 +35,8 @@ public class GridDefaultHeaderTest { public void setUp() { grid = new Grid<>(); - column1 = grid.addColumn("First", Function.identity()); - column2 = grid.addColumn("Second", Function.identity()); + column1 = grid.addColumn("First", SerializableFunction.identity()); + column2 = grid.addColumn("Second", SerializableFunction.identity()); } @Test @@ -62,8 +61,8 @@ public class GridDefaultHeaderTest { public void initialState_updateColumnCaption_defaultHeaderUpdated() { column1.setCaption("1st"); - assertEquals("1st", grid.getDefaultHeaderRow().getCell(column1) - .getText()); + assertEquals("1st", + grid.getDefaultHeaderRow().getCell(column1).getText()); } @Test @@ -71,8 +70,8 @@ public class GridDefaultHeaderTest { grid.setDefaultHeaderRow(grid.appendHeaderRow()); column1.setCaption("1st"); - assertEquals("1st", grid.getDefaultHeaderRow().getCell(column1) - .getText()); + assertEquals("1st", + grid.getDefaultHeaderRow().getCell(column1).getText()); assertEquals("First", grid.getHeaderRow(0).getCell(column1).getText()); } @@ -81,7 +80,6 @@ public class GridDefaultHeaderTest { grid.setDefaultHeaderRow(null); column1.setCaption("1st"); - assertEquals("First", grid.getHeaderRow(0).getCell(column1) - .getText()); + assertEquals("First", grid.getHeaderRow(0).getCell(column1).getText()); } } diff --git a/server/src/test/java/com/vaadin/tests/server/component/grid/GridHeaderFooterTest.java b/server/src/test/java/com/vaadin/tests/server/component/grid/GridHeaderFooterTest.java index a566ae3685..1309297e36 100644 --- a/server/src/test/java/com/vaadin/tests/server/component/grid/GridHeaderFooterTest.java +++ b/server/src/test/java/com/vaadin/tests/server/component/grid/GridHeaderFooterTest.java @@ -20,11 +20,10 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.fail; -import java.util.function.Function; - import org.junit.Before; import org.junit.Test; +import com.vaadin.server.SerializableFunction; import com.vaadin.ui.Grid; import com.vaadin.ui.Grid.Column; import com.vaadin.ui.Grid.HeaderRow; @@ -140,14 +139,16 @@ public class GridHeaderFooterTest { @Test public void addColumn_headerCellAdded() { - Column column = grid.addColumn("Col", Function.identity()); + Column column = grid.addColumn("Col", + SerializableFunction.identity()); assertNotNull(grid.getHeaderRow(0).getCell(column)); } @Test(expected = IllegalArgumentException.class) public void removeColumn_headerCellRemoved() { - Column column = grid.addColumn("Col", Function.identity()); + Column column = grid.addColumn("Col", + SerializableFunction.identity()); grid.removeColumn(column); grid.getHeaderRow(0).getCell(column); diff --git a/server/src/test/java/com/vaadin/tests/server/component/grid/GridTest.java b/server/src/test/java/com/vaadin/tests/server/component/grid/GridTest.java index eec20e2b9d..942228ed34 100644 --- a/server/src/test/java/com/vaadin/tests/server/component/grid/GridTest.java +++ b/server/src/test/java/com/vaadin/tests/server/component/grid/GridTest.java @@ -2,11 +2,10 @@ package com.vaadin.tests.server.component.grid; import static org.junit.Assert.assertEquals; -import java.util.function.Function; - import org.junit.Before; import org.junit.Test; +import com.vaadin.server.SerializableFunction; import com.vaadin.shared.ui.grid.HeightMode; import com.vaadin.ui.Grid; import com.vaadin.ui.renderers.NumberRenderer; @@ -18,9 +17,9 @@ public class GridTest { @Before public void setUp() { grid = new Grid<>(); - grid.addColumn("foo", Function.identity()); + grid.addColumn("foo", SerializableFunction.identity()); grid.addColumn(String::length, new NumberRenderer()); - grid.addColumn("randomColumnId", Function.identity()); + grid.addColumn("randomColumnId", SerializableFunction.identity()); } @Test diff --git a/uitest/src/main/java/com/vaadin/tests/components/grid/GridApplyFilterWhenScrolledDown.java b/uitest/src/main/java/com/vaadin/tests/components/grid/GridApplyFilterWhenScrolledDown.java index 0ce70b722e..b452965765 100644 --- a/uitest/src/main/java/com/vaadin/tests/components/grid/GridApplyFilterWhenScrolledDown.java +++ b/uitest/src/main/java/com/vaadin/tests/components/grid/GridApplyFilterWhenScrolledDown.java @@ -2,8 +2,8 @@ package com.vaadin.tests.components.grid; import java.util.ArrayList; import java.util.List; -import java.util.function.Function; +import com.vaadin.server.SerializableFunction; import com.vaadin.server.VaadinRequest; import com.vaadin.server.data.DataSource; import com.vaadin.tests.components.AbstractTestUI; @@ -16,7 +16,7 @@ public class GridApplyFilterWhenScrolledDown extends AbstractTestUI { protected void setup(VaadinRequest request) { Grid grid = new Grid<>(); - grid.addColumn("Name", Function.identity()); + grid.addColumn("Name", SerializableFunction.identity()); List data = new ArrayList<>(); for (int i = 0; i < 1000; i++) { -- 2.39.5