Change-Id: Iac8f0f48806c0a7c3030bd406e2e533104f26753tags/8.0.0.alpha6
import java.lang.reflect.InvocationTargetException; | import java.lang.reflect.InvocationTargetException; | ||||
import java.lang.reflect.Method; | import java.lang.reflect.Method; | ||||
import java.util.Objects; | 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.BeanUtil; | ||||
import com.vaadin.data.util.converter.Converter; | import com.vaadin.data.util.converter.Converter; | ||||
import com.vaadin.data.validator.BeanValidator; | 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; | import com.vaadin.util.ReflectTools; | ||||
/** | /** | ||||
@Override | @Override | ||||
public default BeanBinding<BEAN, FIELDVALUE, TARGET> withValidator( | public default BeanBinding<BEAN, FIELDVALUE, TARGET> withValidator( | ||||
Predicate<? super TARGET> predicate, String message) { | |||||
SerializablePredicate<? super TARGET> predicate, | |||||
String message) { | |||||
return (BeanBinding<BEAN, FIELDVALUE, TARGET>) Binding.super.withValidator( | return (BeanBinding<BEAN, FIELDVALUE, TARGET>) Binding.super.withValidator( | ||||
predicate, message); | predicate, message); | ||||
} | } | ||||
@Override | @Override | ||||
public default <NEWTARGET> BeanBinding<BEAN, FIELDVALUE, NEWTARGET> withConverter( | public default <NEWTARGET> BeanBinding<BEAN, FIELDVALUE, NEWTARGET> withConverter( | ||||
Function<TARGET, NEWTARGET> toModel, | |||||
Function<NEWTARGET, TARGET> toPresentation) { | |||||
SerializableFunction<TARGET, NEWTARGET> toModel, | |||||
SerializableFunction<NEWTARGET, TARGET> toPresentation) { | |||||
return (BeanBinding<BEAN, FIELDVALUE, NEWTARGET>) Binding.super.withConverter( | return (BeanBinding<BEAN, FIELDVALUE, NEWTARGET>) Binding.super.withConverter( | ||||
toModel, toPresentation); | toModel, toPresentation); | ||||
} | } | ||||
@Override | @Override | ||||
public default <NEWTARGET> BeanBinding<BEAN, FIELDVALUE, NEWTARGET> withConverter( | public default <NEWTARGET> BeanBinding<BEAN, FIELDVALUE, NEWTARGET> withConverter( | ||||
Function<TARGET, NEWTARGET> toModel, | |||||
Function<NEWTARGET, TARGET> toPresentation, | |||||
SerializableFunction<TARGET, NEWTARGET> toModel, | |||||
SerializableFunction<NEWTARGET, TARGET> toPresentation, | |||||
String errorMessage) { | String errorMessage) { | ||||
return (BeanBinding<BEAN, FIELDVALUE, NEWTARGET>) Binding.super.withConverter( | return (BeanBinding<BEAN, FIELDVALUE, NEWTARGET>) Binding.super.withConverter( | ||||
toModel, toPresentation, errorMessage); | toModel, toPresentation, errorMessage); | ||||
* @throws IllegalArgumentException | * @throws IllegalArgumentException | ||||
* if the property has no accessible getter | * 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); | public void bind(String propertyName); | ||||
} | } | ||||
* @throws IllegalArgumentException | * @throws IllegalArgumentException | ||||
* if the property has no accessible getter | * if the property has no accessible getter | ||||
* | * | ||||
* @see #bind(HasValue, java.util.function.Function, | |||||
* java.util.function.BiConsumer) | |||||
* @see #bind(HasValue, SerializableFunction, SerializableBiConsumer) | |||||
*/ | */ | ||||
public <FIELDVALUE> void bind(HasValue<FIELDVALUE> field, | public <FIELDVALUE> void bind(HasValue<FIELDVALUE> field, | ||||
String propertyName) { | String propertyName) { |
import java.util.Optional; | import java.util.Optional; | ||||
import java.util.Set; | import java.util.Set; | ||||
import java.util.function.BiConsumer; | import java.util.function.BiConsumer; | ||||
import java.util.function.Function; | |||||
import java.util.function.Predicate; | |||||
import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||
import com.vaadin.data.util.converter.Converter; | import com.vaadin.data.util.converter.Converter; | ||||
import com.vaadin.data.util.converter.ValueContext; | import com.vaadin.data.util.converter.ValueContext; | ||||
import com.vaadin.event.EventRouter; | import com.vaadin.event.EventRouter; | ||||
import com.vaadin.server.ErrorMessage; | 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.server.UserError; | ||||
import com.vaadin.shared.Registration; | import com.vaadin.shared.Registration; | ||||
import com.vaadin.ui.AbstractComponent; | import com.vaadin.ui.AbstractComponent; | ||||
* @throws IllegalStateException | * @throws IllegalStateException | ||||
* if {@code bind} has already been called on this binding | * if {@code bind} has already been called on this binding | ||||
*/ | */ | ||||
public void bind(Function<BEAN, TARGET> getter, | |||||
BiConsumer<BEAN, TARGET> setter); | |||||
public void bind(SerializableFunction<BEAN, TARGET> getter, | |||||
com.vaadin.server.SerializableBiConsumer<BEAN, TARGET> setter); | |||||
/** | /** | ||||
* Adds a validator to this binding. Validators are applied, in | * Adds a validator to this binding. Validators are applied, in | ||||
/** | /** | ||||
* A convenience method to add a validator to this binding using the | * 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. | |||||
* <p> | * <p> | ||||
* Validators are applied, in registration order, when the field value | * Validators are applied, in registration order, when the field value | ||||
* is saved to the backing property. If any validator returns a failure, | * is saved to the backing property. If any validator returns a failure, | ||||
* the property value is not updated. | * the property value is not updated. | ||||
* | * | ||||
* @see #withValidator(Validator) | * @see #withValidator(Validator) | ||||
* @see Validator#from(Predicate, String) | |||||
* @see Validator#from(SerializablePredicate, String) | |||||
* | * | ||||
* @param predicate | * @param predicate | ||||
* the predicate performing validation, not null | * the predicate performing validation, not null | ||||
* if {@code bind} has already been called | * if {@code bind} has already been called | ||||
*/ | */ | ||||
public default Binding<BEAN, FIELDVALUE, TARGET> withValidator( | public default Binding<BEAN, FIELDVALUE, TARGET> withValidator( | ||||
Predicate<? super TARGET> predicate, String message) { | |||||
SerializablePredicate<? super TARGET> predicate, | |||||
String message) { | |||||
return withValidator(Validator.from(predicate, message)); | return withValidator(Validator.from(predicate, message)); | ||||
} | } | ||||
* which must match the current target data type of the binding, and a | * 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 | * model type, which can be any data type and becomes the new target | ||||
* type of the binding. When invoking | * 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. | |||||
* <p> | * <p> | ||||
* For instance, a {@code TextField} can be bound to an integer-typed | * For instance, a {@code TextField} can be bound to an integer-typed | ||||
* property using an appropriate converter such as a | * property using an appropriate converter such as a | ||||
* type, which must match the current target data type of the binding, | * 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 | * and a model type, which can be any data type and becomes the new | ||||
* target type of the binding. When invoking | * 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. | |||||
* <p> | * <p> | ||||
* For instance, a {@code TextField} can be bound to an integer-typed | * For instance, a {@code TextField} can be bound to an integer-typed | ||||
* property using appropriate functions such as: | * property using appropriate functions such as: | ||||
* if {@code bind} has already been called | * if {@code bind} has already been called | ||||
*/ | */ | ||||
public default <NEWTARGET> Binding<BEAN, FIELDVALUE, NEWTARGET> withConverter( | public default <NEWTARGET> Binding<BEAN, FIELDVALUE, NEWTARGET> withConverter( | ||||
Function<TARGET, NEWTARGET> toModel, | |||||
Function<NEWTARGET, TARGET> toPresentation) { | |||||
SerializableFunction<TARGET, NEWTARGET> toModel, | |||||
SerializableFunction<NEWTARGET, TARGET> toPresentation) { | |||||
return withConverter(Converter.from(toModel, toPresentation, | return withConverter(Converter.from(toModel, toPresentation, | ||||
exception -> exception.getMessage())); | exception -> exception.getMessage())); | ||||
} | } | ||||
* type, which must match the current target data type of the binding, | * 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 | * and a model type, which can be any data type and becomes the new | ||||
* target type of the binding. When invoking | * 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. | |||||
* <p> | * <p> | ||||
* For instance, a {@code TextField} can be bound to an integer-typed | * For instance, a {@code TextField} can be bound to an integer-typed | ||||
* property using appropriate functions such as: | * property using appropriate functions such as: | ||||
* if {@code bind} has already been called | * if {@code bind} has already been called | ||||
*/ | */ | ||||
public default <NEWTARGET> Binding<BEAN, FIELDVALUE, NEWTARGET> withConverter( | public default <NEWTARGET> Binding<BEAN, FIELDVALUE, NEWTARGET> withConverter( | ||||
Function<TARGET, NEWTARGET> toModel, | |||||
Function<NEWTARGET, TARGET> toPresentation, | |||||
SerializableFunction<TARGET, NEWTARGET> toModel, | |||||
SerializableFunction<NEWTARGET, TARGET> toPresentation, | |||||
String errorMessage) { | String errorMessage) { | ||||
return withConverter(Converter.from(toModel, toPresentation, | return withConverter(Converter.from(toModel, toPresentation, | ||||
exception -> errorMessage)); | exception -> errorMessage)); | ||||
private ValidationStatusHandler statusHandler; | private ValidationStatusHandler statusHandler; | ||||
private boolean isStatusHandlerChanged; | private boolean isStatusHandlerChanged; | ||||
private Function<BEAN, TARGET> getter; | |||||
private BiConsumer<BEAN, TARGET> setter; | |||||
private SerializableFunction<BEAN, TARGET> getter; | |||||
private SerializableBiConsumer<BEAN, TARGET> setter; | |||||
/** | /** | ||||
* Contains all converters and validators chained together in the | * Contains all converters and validators chained together in the | ||||
} | } | ||||
@Override | @Override | ||||
public void bind(Function<BEAN, TARGET> getter, | |||||
BiConsumer<BEAN, TARGET> setter) { | |||||
public void bind(SerializableFunction<BEAN, TARGET> getter, | |||||
SerializableBiConsumer<BEAN, TARGET> setter) { | |||||
checkUnbound(); | checkUnbound(); | ||||
Objects.requireNonNull(getter, "getter cannot be null"); | Objects.requireNonNull(getter, "getter cannot be null"); | ||||
/** | /** | ||||
* Creates a new binding for the given field. The returned binding may be | * 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 | * {@link Binding#bind(Function, BiConsumer) Binding.bind} which completes | ||||
* the binding. Until {@code Binding.bind} is called, the binding has no | * the binding. Until {@code Binding.bind} is called, the binding has no | ||||
* effect. | * effect. | ||||
* automatically change {@code null} to a null representation provided by | * automatically change {@code null} to a null representation provided by | ||||
* {@link HasValue#getEmptyValue()}. This conversion is one-way only, if you | * {@link HasValue#getEmptyValue()}. This conversion is one-way only, if you | ||||
* want to have a two-way mapping back to {@code null}, use | * 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 <FIELDVALUE> | * @param <FIELDVALUE> | ||||
* the value type of the field | * the value type of the field | ||||
* the field to be bound, not null | * the field to be bound, not null | ||||
* @return the new binding | * @return the new binding | ||||
* | * | ||||
* @see #bind(HasValue, Function, BiConsumer) | |||||
* @see #bind(HasValue, SerializableFunction, SerializableBiConsumer) | |||||
*/ | */ | ||||
public <FIELDVALUE> Binding<BEAN, FIELDVALUE, FIELDVALUE> forField( | public <FIELDVALUE> Binding<BEAN, FIELDVALUE, FIELDVALUE> forField( | ||||
HasValue<FIELDVALUE> field) { | HasValue<FIELDVALUE> field) { | ||||
* if read-only | * if read-only | ||||
*/ | */ | ||||
public <FIELDVALUE> void bind(HasValue<FIELDVALUE> field, | public <FIELDVALUE> void bind(HasValue<FIELDVALUE> field, | ||||
Function<BEAN, FIELDVALUE> getter, | |||||
BiConsumer<BEAN, FIELDVALUE> setter) { | |||||
SerializableFunction<BEAN, FIELDVALUE> getter, | |||||
SerializableBiConsumer<BEAN, FIELDVALUE> setter) { | |||||
forField(field).bind(getter, setter); | forField(field).bind(getter, setter); | ||||
} | } | ||||
* <li>{@link #load(Object)} is called | * <li>{@link #load(Object)} is called | ||||
* <li>{@link #bind(Object)} is called | * <li>{@link #bind(Object)} is called | ||||
* <li>{@link #unbind(Object)} is called | * <li>{@link #unbind(Object)} is called | ||||
* <li>{@link Binding#bind(Function, BiConsumer)} is called | |||||
* <li>{@link Binding#bind(SerializableFunction, SerializableBiConsumer)} is | |||||
* called | |||||
* <li>{@link Binder#validate()} or {@link Binding#validate()} is called | * <li>{@link Binder#validate()} or {@link Binding#validate()} is called | ||||
* </ul> | * </ul> | ||||
* | * |
import java.util.function.Function; | import java.util.function.Function; | ||||
import java.util.function.Predicate; | import java.util.function.Predicate; | ||||
import com.vaadin.server.SerializablePredicate; | |||||
/** | /** | ||||
* A functional interface for validating user input or other potentially invalid | * A functional interface for validating user input or other potentially invalid | ||||
* data. When a validator instance is applied to a value of the corresponding | * data. When a validator instance is applied to a value of the corresponding | ||||
* the message returned if validation fails, not null | * the message returned if validation fails, not null | ||||
* @return the new validator using the function | * @return the new validator using the function | ||||
*/ | */ | ||||
public static <T> Validator<T> from(Predicate<T> guard, | |||||
public static <T> Validator<T> from(SerializablePredicate<T> guard, | |||||
String errorMessage) { | String errorMessage) { | ||||
Objects.requireNonNull(guard, "guard cannot be null"); | Objects.requireNonNull(guard, "guard cannot be null"); | ||||
Objects.requireNonNull(errorMessage, "errorMessage cannot be null"); | Objects.requireNonNull(errorMessage, "errorMessage cannot be null"); |
import com.vaadin.data.Binder.Binding; | import com.vaadin.data.Binder.Binding; | ||||
import com.vaadin.data.Result; | import com.vaadin.data.Result; | ||||
import com.vaadin.server.SerializableFunction; | |||||
/** | /** | ||||
* Interface that implements conversion between a model and a presentation type. | * Interface that implements conversion between a model and a presentation type. | ||||
* @see Result | * @see Result | ||||
* @see Function | * @see Function | ||||
*/ | */ | ||||
public static <P, M> Converter<P, M> from(Function<P, M> toModel, | |||||
Function<M, P> toPresentation, | |||||
Function<Exception, String> onError) { | |||||
public static <P, M> Converter<P, M> from( | |||||
SerializableFunction<P, M> toModel, | |||||
SerializableFunction<M, P> toPresentation, | |||||
SerializableFunction<Exception, String> onError) { | |||||
return from(val -> Result.of(() -> toModel.apply(val), onError), | return from(val -> Result.of(() -> toModel.apply(val), onError), | ||||
toPresentation); | toPresentation); | ||||
* | * | ||||
* @see Function | * @see Function | ||||
*/ | */ | ||||
public static <P, M> Converter<P, M> from(Function<P, Result<M>> toModel, | |||||
Function<M, P> toPresentation) { | |||||
public static <P, M> Converter<P, M> from( | |||||
SerializableFunction<P, Result<M>> toModel, | |||||
SerializableFunction<M, P> toPresentation) { | |||||
return new Converter<P, M>() { | return new Converter<P, M>() { | ||||
@Override | @Override |
package com.vaadin.data.validator; | package com.vaadin.data.validator; | ||||
import java.util.Objects; | import java.util.Objects; | ||||
import java.util.function.Function; | |||||
import com.vaadin.data.Result; | import com.vaadin.data.Result; | ||||
import com.vaadin.data.Validator; | import com.vaadin.data.Validator; | ||||
import com.vaadin.server.SerializableFunction; | |||||
/** | /** | ||||
* An abstract base class for typed validators. | * An abstract base class for typed validators. | ||||
*/ | */ | ||||
public abstract class AbstractValidator<T> implements Validator<T> { | public abstract class AbstractValidator<T> implements Validator<T> { | ||||
private Function<T, String> messageProvider; | |||||
private SerializableFunction<T, String> messageProvider; | |||||
/** | /** | ||||
* Constructs a validator with the given error message. The substring "{0}" | * Constructs a validator with the given error message. The substring "{0}" |
/* | |||||
* 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 <T> | |||||
* the type of the first argument to the operation | |||||
* @param <U> | |||||
* the type of the second argument to the operation | |||||
* | |||||
* @since 8.0 | |||||
* @author Vaadin Ltd | |||||
* | |||||
*/ | |||||
@FunctionalInterface | |||||
public interface SerializableBiConsumer<T, U> | |||||
extends BiConsumer<T, U>, Serializable { | |||||
// Only method inherited from BiConsumer | |||||
} |
/* | |||||
* 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 <T> | |||||
* the type of objects that may be compared by this comparator | |||||
* @since 8.0 | |||||
* | |||||
*/ | |||||
@FunctionalInterface | |||||
public interface SerializableComparator<T> extends Comparator<T>, Serializable { | |||||
/** | |||||
* Returns a {@link SerializableComparator} instance which delegates its | |||||
* logic to the provided {@code comparator}. | |||||
* | |||||
* @param comparator | |||||
* comparator to convert | |||||
* @param <T> | |||||
* the type of objects that may be compared by this comparator | |||||
* @param <C> | |||||
* the comparator type | |||||
* @return a SerializableComparator view of the {@code comparator} | |||||
*/ | |||||
static <C extends Comparator<T> & Serializable, T> SerializableComparator<T> asInstance( | |||||
C comparator) { | |||||
return (arg1, arg2) -> comparator.compare(arg1, arg2); | |||||
} | |||||
} |
/* | |||||
* 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 <T> | |||||
* the type of the input to the function | |||||
* @param <R> | |||||
* the type of the result of the function | |||||
*/ | |||||
@FunctionalInterface | |||||
public interface SerializableFunction<T, R> | |||||
extends Function<T, R>, Serializable { | |||||
/** | |||||
* Returns a function that always returns its input argument. | |||||
* | |||||
* @param <T> | |||||
* the type of the input and output objects to the function | |||||
* @return a function that always returns its input argument | |||||
*/ | |||||
static <T> SerializableFunction<T, T> identity() { | |||||
return t -> t; | |||||
} | |||||
} |
/* | |||||
* 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 <T> | |||||
* the type of the input to the predicate | |||||
* | |||||
*/ | |||||
public interface SerializablePredicate<T> extends Predicate<T>, Serializable { | |||||
// Only method inherited from Function | |||||
} |
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.Objects; | import java.util.Objects; | ||||
import java.util.function.Function; | |||||
import java.util.stream.Stream; | import java.util.stream.Stream; | ||||
import com.vaadin.server.SerializableFunction; | |||||
/** | /** | ||||
* A {@link DataSource} for any back end. | * A {@link DataSource} for any back end. | ||||
* | * | ||||
*/ | */ | ||||
public class BackEndDataSource<T> extends AbstractDataSource<T> { | public class BackEndDataSource<T> extends AbstractDataSource<T> { | ||||
private Function<Query, Stream<T>> request; | |||||
private Function<Query, Integer> sizeCallback; | |||||
private SerializableFunction<Query, Stream<T>> request; | |||||
private SerializableFunction<Query, Integer> sizeCallback; | |||||
/** | /** | ||||
* Constructs a new DataSource to request data from an arbitrary back end | * Constructs a new DataSource to request data from an arbitrary back end | ||||
* @param sizeCallback | * @param sizeCallback | ||||
* function that return the amount of data in back end for query | * function that return the amount of data in back end for query | ||||
*/ | */ | ||||
public BackEndDataSource(Function<Query, Stream<T>> request, | |||||
Function<Query, Integer> sizeCallback) { | |||||
public BackEndDataSource(SerializableFunction<Query, Stream<T>> request, | |||||
SerializableFunction<Query, Integer> sizeCallback) { | |||||
Objects.requireNonNull(request, "Request function can't be null"); | Objects.requireNonNull(request, "Request function can't be null"); | ||||
Objects.requireNonNull(sizeCallback, "Size callback can't be null"); | Objects.requireNonNull(sizeCallback, "Size callback can't be null"); | ||||
this.request = request; | this.request = request; |
import com.vaadin.server.AbstractExtension; | import com.vaadin.server.AbstractExtension; | ||||
import com.vaadin.server.KeyMapper; | import com.vaadin.server.KeyMapper; | ||||
import com.vaadin.server.SerializablePredicate; | |||||
import com.vaadin.shared.Range; | import com.vaadin.shared.Range; | ||||
import com.vaadin.shared.Registration; | import com.vaadin.shared.Registration; | ||||
import com.vaadin.shared.data.DataCommunicatorClientRpc; | import com.vaadin.shared.data.DataCommunicatorClientRpc; | ||||
private Range pushRows = Range.withLength(0, 40); | private Range pushRows = Range.withLength(0, 40); | ||||
private Comparator<T> inMemorySorting; | private Comparator<T> inMemorySorting; | ||||
private Predicate<T> inMemoryFilter; | |||||
private SerializablePredicate<T> inMemoryFilter; | |||||
private List<SortOrder<String>> backEndSorting = new ArrayList<>(); | private List<SortOrder<String>> backEndSorting = new ArrayList<>(); | ||||
private DataCommunicatorClientRpc rpc; | private DataCommunicatorClientRpc rpc; | ||||
* @param predicate | * @param predicate | ||||
* predicate used to filter data | * predicate used to filter data | ||||
*/ | */ | ||||
public void setInMemoryFilter(Predicate<T> predicate) { | |||||
public void setInMemoryFilter(SerializablePredicate<T> predicate) { | |||||
inMemoryFilter = predicate; | inMemoryFilter = predicate; | ||||
reset(); | reset(); | ||||
} | } |
import com.vaadin.event.selection.MultiSelectionListener; | import com.vaadin.event.selection.MultiSelectionListener; | ||||
import com.vaadin.server.Resource; | import com.vaadin.server.Resource; | ||||
import com.vaadin.server.ResourceReference; | import com.vaadin.server.ResourceReference; | ||||
import com.vaadin.server.SerializablePredicate; | |||||
import com.vaadin.server.data.DataGenerator; | import com.vaadin.server.data.DataGenerator; | ||||
import com.vaadin.shared.Registration; | import com.vaadin.shared.Registration; | ||||
import com.vaadin.shared.data.selection.MultiSelectServerRpc; | import com.vaadin.shared.data.selection.MultiSelectServerRpc; | ||||
* The item enabled status provider. It is up to the implementing class to | * The item enabled status provider. It is up to the implementing class to | ||||
* support this or not. | * support this or not. | ||||
*/ | */ | ||||
private Predicate<T> itemEnabledProvider = item -> true; | |||||
private SerializablePredicate<T> itemEnabledProvider = item -> true; | |||||
/** | /** | ||||
* Creates a new multi select with an empty data source. | * Creates a new multi select with an empty data source. | ||||
* Returns the item enabled provider for this multiselect. | * Returns the item enabled provider for this multiselect. | ||||
* <p> | * <p> | ||||
* <em>Implementation note:</em> Override this method and | * <em>Implementation note:</em> 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} | * @return the item enabled provider, not {@code null} | ||||
* @see #setItemEnabledProvider(Predicate) | * @see #setItemEnabledProvider(Predicate) | ||||
*/ | */ | ||||
protected Predicate<T> getItemEnabledProvider() { | |||||
protected SerializablePredicate<T> getItemEnabledProvider() { | |||||
return itemEnabledProvider; | return itemEnabledProvider; | ||||
} | } | ||||
* @param itemEnabledProvider | * @param itemEnabledProvider | ||||
* the item enabled provider to set, not {@code null} | * the item enabled provider to set, not {@code null} | ||||
*/ | */ | ||||
protected void setItemEnabledProvider(Predicate<T> itemEnabledProvider) { | |||||
protected void setItemEnabledProvider( | |||||
SerializablePredicate<T> itemEnabledProvider) { | |||||
Objects.requireNonNull(itemEnabledProvider); | Objects.requireNonNull(itemEnabledProvider); | ||||
this.itemEnabledProvider = itemEnabledProvider; | this.itemEnabledProvider = itemEnabledProvider; | ||||
} | } |
package com.vaadin.ui; | package com.vaadin.ui; | ||||
import java.util.Collection; | import java.util.Collection; | ||||
import java.util.function.Predicate; | |||||
import com.vaadin.data.Listing; | import com.vaadin.data.Listing; | ||||
import com.vaadin.server.SerializablePredicate; | |||||
import com.vaadin.server.data.DataSource; | import com.vaadin.server.data.DataSource; | ||||
import com.vaadin.shared.ui.optiongroup.CheckBoxGroupState; | import com.vaadin.shared.ui.optiongroup.CheckBoxGroupState; | ||||
} | } | ||||
@Override | @Override | ||||
public Predicate<T> getItemEnabledProvider() { | |||||
public SerializablePredicate<T> getItemEnabledProvider() { | |||||
return super.getItemEnabledProvider(); | return super.getItemEnabledProvider(); | ||||
} | } | ||||
@Override | @Override | ||||
public void setItemEnabledProvider(Predicate<T> itemEnabledProvider) { | |||||
public void setItemEnabledProvider( | |||||
SerializablePredicate<T> itemEnabledProvider) { | |||||
super.setItemEnabledProvider(itemEnabledProvider); | super.setItemEnabledProvider(itemEnabledProvider); | ||||
} | } | ||||
} | } |
import java.util.Objects; | import java.util.Objects; | ||||
import java.util.Optional; | import java.util.Optional; | ||||
import java.util.Set; | import java.util.Set; | ||||
import java.util.function.BinaryOperator; | |||||
import java.util.function.Function; | import java.util.function.Function; | ||||
import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||
import java.util.stream.Stream; | import java.util.stream.Stream; | ||||
import com.vaadin.event.EventListener; | import com.vaadin.event.EventListener; | ||||
import com.vaadin.server.EncodeResult; | import com.vaadin.server.EncodeResult; | ||||
import com.vaadin.server.JsonCodec; | import com.vaadin.server.JsonCodec; | ||||
import com.vaadin.server.SerializableComparator; | |||||
import com.vaadin.server.SerializableFunction; | |||||
import com.vaadin.server.data.SortOrder; | import com.vaadin.server.data.SortOrder; | ||||
import com.vaadin.shared.MouseEventDetails; | import com.vaadin.shared.MouseEventDetails; | ||||
import com.vaadin.shared.Registration; | import com.vaadin.shared.Registration; | ||||
*/ | */ | ||||
@FunctionalInterface | @FunctionalInterface | ||||
public interface DescriptionGenerator<T> | public interface DescriptionGenerator<T> | ||||
extends Function<T, String>, Serializable { | |||||
extends SerializableFunction<T, String> { | |||||
} | } | ||||
/** | /** | ||||
// Set sort orders | // Set sort orders | ||||
// In-memory comparator | // In-memory comparator | ||||
Comparator<T> comparator = sortOrder.stream() | |||||
BinaryOperator<SerializableComparator<T>> operator = (comparator1, | |||||
comparator2) -> SerializableComparator.asInstance( | |||||
(Comparator<T> & Serializable) comparator1 | |||||
.thenComparing(comparator2)); | |||||
SerializableComparator<T> comparator = sortOrder.stream() | |||||
.map(order -> order.getSorted() | .map(order -> order.getSorted() | ||||
.getComparator(order.getDirection())) | .getComparator(order.getDirection())) | ||||
.reduce((x, y) -> 0, Comparator::thenComparing); | |||||
.reduce((x, y) -> 0, operator); | |||||
getDataCommunicator().setInMemorySorting(comparator); | getDataCommunicator().setInMemorySorting(comparator); | ||||
// Back-end sort properties | // Back-end sort properties | ||||
*/ | */ | ||||
public static class Column<T, V> extends AbstractGridExtension<T> { | public static class Column<T, V> extends AbstractGridExtension<T> { | ||||
private final Function<T, ? extends V> valueProvider; | |||||
private final SerializableFunction<T, ? extends V> valueProvider; | |||||
private Function<SortDirection, Stream<SortOrder<String>>> sortOrderProvider; | |||||
private Comparator<T> comparator; | |||||
private SerializableFunction<SortDirection, Stream<SortOrder<String>>> sortOrderProvider; | |||||
private SerializableComparator<T> comparator; | |||||
private StyleGenerator<T> styleGenerator = item -> null; | private StyleGenerator<T> styleGenerator = item -> null; | ||||
private DescriptionGenerator<T> descriptionGenerator; | private DescriptionGenerator<T> descriptionGenerator; | ||||
* @param renderer | * @param renderer | ||||
* the type of value | * the type of value | ||||
*/ | */ | ||||
protected Column(String caption, Function<T, ? extends V> valueProvider, | |||||
protected Column(String caption, | |||||
SerializableFunction<T, ? extends V> valueProvider, | |||||
Renderer<V> renderer) { | Renderer<V> renderer) { | ||||
Objects.requireNonNull(caption, "Header caption can't be null"); | Objects.requireNonNull(caption, "Header caption can't be null"); | ||||
Objects.requireNonNull(valueProvider, | Objects.requireNonNull(valueProvider, | ||||
* the comparator to use when sorting data in this column | * the comparator to use when sorting data in this column | ||||
* @return this column | * @return this column | ||||
*/ | */ | ||||
public Column<T, V> setComparator(Comparator<T> comparator) { | |||||
public Column<T, V> setComparator( | |||||
SerializableComparator<T> comparator) { | |||||
Objects.requireNonNull(comparator, "Comparator can't be null"); | Objects.requireNonNull(comparator, "Comparator can't be null"); | ||||
this.comparator = comparator; | this.comparator = comparator; | ||||
return this; | return this; | ||||
* the direction this column is sorted by | * the direction this column is sorted by | ||||
* @return comparator for this column | * @return comparator for this column | ||||
*/ | */ | ||||
public Comparator<T> getComparator(SortDirection sortDirection) { | |||||
public SerializableComparator<T> getComparator( | |||||
SortDirection sortDirection) { | |||||
Objects.requireNonNull(comparator, | Objects.requireNonNull(comparator, | ||||
"No comparator defined for sorted column."); | "No comparator defined for sorted column."); | ||||
boolean reverse = sortDirection != SortDirection.ASCENDING; | boolean reverse = sortDirection != SortDirection.ASCENDING; | ||||
return reverse ? comparator.reversed() : comparator; | |||||
return reverse ? (t1, t2) -> comparator.reversed().compare(t1, t2) | |||||
: comparator; | |||||
} | } | ||||
/** | /** | ||||
* @return this column | * @return this column | ||||
*/ | */ | ||||
public Column<T, V> setSortOrderProvider( | public Column<T, V> setSortOrderProvider( | ||||
Function<SortDirection, Stream<SortOrder<String>>> provider) { | |||||
SerializableFunction<SortDirection, Stream<SortOrder<String>>> provider) { | |||||
Objects.requireNonNull(provider, | Objects.requireNonNull(provider, | ||||
"Sort order provider can't be null"); | "Sort order provider can't be null"); | ||||
sortOrderProvider = provider; | sortOrderProvider = provider; | ||||
* @see {@link AbstractRenderer} | * @see {@link AbstractRenderer} | ||||
*/ | */ | ||||
public <V> Column<T, V> addColumn(String identifier, | public <V> Column<T, V> addColumn(String identifier, | ||||
Function<T, ? extends V> valueProvider, | |||||
SerializableFunction<T, ? extends V> valueProvider, | |||||
AbstractRenderer<? super T, V> renderer) | AbstractRenderer<? super T, V> renderer) | ||||
throws IllegalArgumentException { | throws IllegalArgumentException { | ||||
if (columnKeys.containsKey(identifier)) { | if (columnKeys.containsKey(identifier)) { | ||||
* if the same identifier is used for multiple columns | * if the same identifier is used for multiple columns | ||||
*/ | */ | ||||
public Column<T, String> addColumn(String identifier, | public Column<T, String> addColumn(String identifier, | ||||
Function<T, String> valueProvider) { | |||||
SerializableFunction<T, String> valueProvider) { | |||||
return addColumn(identifier, valueProvider, new TextRenderer()); | return addColumn(identifier, valueProvider, new TextRenderer()); | ||||
} | } | ||||
* | * | ||||
* @return the new column | * @return the new column | ||||
*/ | */ | ||||
public Column<T, String> addColumn(Function<T, String> valueProvider) { | |||||
public Column<T, String> addColumn( | |||||
SerializableFunction<T, String> valueProvider) { | |||||
return addColumn(getGeneratedIdentifier(), valueProvider, | return addColumn(getGeneratedIdentifier(), valueProvider, | ||||
new TextRenderer()); | new TextRenderer()); | ||||
} | } | ||||
* | * | ||||
* @see {@link AbstractRenderer} | * @see {@link AbstractRenderer} | ||||
*/ | */ | ||||
public <V> Column<T, V> addColumn(Function<T, ? extends V> valueProvider, | |||||
public <V> Column<T, V> addColumn( | |||||
SerializableFunction<T, ? extends V> valueProvider, | |||||
AbstractRenderer<? super T, V> renderer) { | AbstractRenderer<? super T, V> renderer) { | ||||
return addColumn(getGeneratedIdentifier(), valueProvider, renderer); | return addColumn(getGeneratedIdentifier(), valueProvider, renderer); | ||||
} | } | ||||
boolean userOriginated) { | boolean userOriginated) { | ||||
fireEvent(new ColumnResizeEvent(this, column, userOriginated)); | fireEvent(new ColumnResizeEvent(this, column, userOriginated)); | ||||
} | } | ||||
} | } |
*/ | */ | ||||
package com.vaadin.ui; | package com.vaadin.ui; | ||||
import java.io.Serializable; | |||||
import java.util.function.Function; | |||||
import com.vaadin.server.Resource; | import com.vaadin.server.Resource; | ||||
import com.vaadin.server.SerializableFunction; | |||||
/** | /** | ||||
* A callback interface for generating icons for an item. | * A callback interface for generating icons for an item. | ||||
* item type for which the icon is generated | * item type for which the icon is generated | ||||
*/ | */ | ||||
@FunctionalInterface | @FunctionalInterface | ||||
public interface IconGenerator<T> extends Function<T, Resource>, Serializable { | |||||
public interface IconGenerator<T> extends SerializableFunction<T, Resource> { | |||||
/** | /** | ||||
* Gets an icon resource for the {@code item}. | * Gets an icon resource for the {@code item}. |
*/ | */ | ||||
package com.vaadin.ui; | 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 | * {@link ItemCaptionGenerator} can be used to customize the string shown to the | ||||
*/ | */ | ||||
@FunctionalInterface | @FunctionalInterface | ||||
public interface ItemCaptionGenerator<T> | public interface ItemCaptionGenerator<T> | ||||
extends Function<T, String>, Serializable { | |||||
extends SerializableFunction<T, String> { | |||||
/** | /** | ||||
* Gets a caption for the {@code item}. | * Gets a caption for the {@code item}. |
import java.util.Collection; | import java.util.Collection; | ||||
import java.util.Objects; | import java.util.Objects; | ||||
import java.util.function.Predicate; | |||||
import com.vaadin.data.Listing; | import com.vaadin.data.Listing; | ||||
import com.vaadin.server.Resource; | import com.vaadin.server.Resource; | ||||
import com.vaadin.server.ResourceReference; | import com.vaadin.server.ResourceReference; | ||||
import com.vaadin.server.SerializablePredicate; | |||||
import com.vaadin.server.data.DataGenerator; | import com.vaadin.server.data.DataGenerator; | ||||
import com.vaadin.server.data.DataSource; | import com.vaadin.server.data.DataSource; | ||||
import com.vaadin.shared.ui.ListingJsonConstants; | import com.vaadin.shared.ui.ListingJsonConstants; | ||||
private ItemCaptionGenerator<T> itemCaptionGenerator = String::valueOf; | private ItemCaptionGenerator<T> itemCaptionGenerator = String::valueOf; | ||||
private Predicate<T> itemEnabledProvider = item -> true; | |||||
private SerializablePredicate<T> itemEnabledProvider = item -> true; | |||||
/** | /** | ||||
* Constructs a new RadioButtonGroup with caption. | * Constructs a new RadioButtonGroup with caption. | ||||
* @return the item enabled predicate | * @return the item enabled predicate | ||||
* @see #setItemEnabledProvider | * @see #setItemEnabledProvider | ||||
*/ | */ | ||||
public Predicate<T> getItemEnabledProvider() { | |||||
public SerializablePredicate<T> getItemEnabledProvider() { | |||||
return itemEnabledProvider; | return itemEnabledProvider; | ||||
} | } | ||||
* @param itemEnabledProvider | * @param itemEnabledProvider | ||||
* the item enable predicate, not null | * the item enable predicate, not null | ||||
*/ | */ | ||||
public void setItemEnabledProvider(Predicate<T> itemEnabledProvider) { | |||||
public void setItemEnabledProvider( | |||||
SerializablePredicate<T> itemEnabledProvider) { | |||||
Objects.requireNonNull(itemEnabledProvider); | Objects.requireNonNull(itemEnabledProvider); | ||||
this.itemEnabledProvider = itemEnabledProvider; | this.itemEnabledProvider = itemEnabledProvider; | ||||
} | } |
*/ | */ | ||||
package com.vaadin.ui; | 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. | * A callback interface for generating custom CSS class names for items. | ||||
* @author Vaadin Ltd | * @author Vaadin Ltd | ||||
*/ | */ | ||||
@FunctionalInterface | @FunctionalInterface | ||||
public interface StyleGenerator<T> extends Function<T, String>, Serializable { | |||||
public interface StyleGenerator<T> extends SerializableFunction<T, String> { | |||||
/** | /** | ||||
* Gets a class name for the {@code item}. | * Gets a class name for the {@code item}. |
import java.util.List; | import java.util.List; | ||||
import java.util.concurrent.atomic.AtomicBoolean; | import java.util.concurrent.atomic.AtomicBoolean; | ||||
import java.util.function.Predicate; | |||||
import org.junit.Assert; | import org.junit.Assert; | ||||
import org.junit.Before; | import org.junit.Before; | ||||
import com.vaadin.data.validator.NotEmptyValidator; | import com.vaadin.data.validator.NotEmptyValidator; | ||||
import com.vaadin.server.AbstractErrorMessage; | import com.vaadin.server.AbstractErrorMessage; | ||||
import com.vaadin.server.ErrorMessage; | import com.vaadin.server.ErrorMessage; | ||||
import com.vaadin.server.SerializablePredicate; | |||||
import com.vaadin.server.UserError; | import com.vaadin.server.UserError; | ||||
import com.vaadin.tests.data.bean.Person; | import com.vaadin.tests.data.bean.Person; | ||||
import com.vaadin.ui.Label; | import com.vaadin.ui.Label; | ||||
@Test | @Test | ||||
public void binderLoad_withCrossFieldValidation_clearsErrors() { | public void binderLoad_withCrossFieldValidation_clearsErrors() { | ||||
TextField lastNameField = new TextField(); | TextField lastNameField = new TextField(); | ||||
final Predicate<String> lengthPredicate = v -> v.length() > 2; | |||||
final SerializablePredicate<String> lengthPredicate = v -> v | |||||
.length() > 2; | |||||
Binding<Person, String, String> firstNameBinding = binder | Binding<Person, String, String> firstNameBinding = binder | ||||
.forField(nameField).withValidator(lengthPredicate, "length"); | .forField(nameField).withValidator(lengthPredicate, "length"); |
package com.vaadin.tests.data.converter; | package com.vaadin.tests.data.converter; | ||||
import java.util.function.Function; | |||||
import org.junit.Assert; | import org.junit.Assert; | ||||
import org.junit.Test; | import org.junit.Test; | ||||
import com.vaadin.data.Result; | import com.vaadin.data.Result; | ||||
import com.vaadin.data.util.converter.Converter; | import com.vaadin.data.util.converter.Converter; | ||||
import com.vaadin.data.util.converter.ValueContext; | import com.vaadin.data.util.converter.ValueContext; | ||||
import com.vaadin.server.SerializableFunction; | |||||
public class ConverterTest { | public class ConverterTest { | ||||
Function<String, Result<String>> toModel = presentation -> { | |||||
SerializableFunction<String, Result<String>> toModel = presentation -> { | |||||
if (presentation.startsWith("presentation-")) { | if (presentation.startsWith("presentation-")) { | ||||
return Result.ok(presentation.substring("presentation-".length())); | return Result.ok(presentation.substring("presentation-".length())); | ||||
} else { | } else { | ||||
} | } | ||||
}; | }; | ||||
Function<String, String> toPresentation = model -> "presentation-" + model; | |||||
SerializableFunction<String, String> toPresentation = model -> "presentation-" | |||||
+ model; | |||||
Converter<String, String> converter = Converter.from(toModel, | Converter<String, String> converter = Converter.from(toModel, | ||||
toPresentation); | toPresentation); |
package com.vaadin.tests.server; | package com.vaadin.tests.server; | ||||
import java.io.ByteArrayInputStream; | |||||
import java.io.ByteArrayOutputStream; | |||||
import java.io.File; | import java.io.File; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.ObjectInputStream; | |||||
import java.io.ObjectOutputStream; | |||||
import java.io.Serializable; | 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.Method; | ||||
import java.lang.reflect.Modifier; | |||||
import java.lang.reflect.Type; | |||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.Collection; | import java.util.Collection; | ||||
import java.util.Collections; | import java.util.Collections; | ||||
import java.util.Enumeration; | import java.util.Enumeration; | ||||
import java.util.Iterator; | import java.util.Iterator; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.Optional; | |||||
import java.util.jar.JarEntry; | import java.util.jar.JarEntry; | ||||
import java.util.jar.JarFile; | import java.util.jar.JarFile; | ||||
import java.util.stream.Collectors; | |||||
import java.util.stream.Stream; | |||||
import org.junit.Assert; | import org.junit.Assert; | ||||
import org.junit.Test; | import org.junit.Test; | ||||
import com.vaadin.ui.Component; | |||||
public class ClassesSerializableTest { | public class ClassesSerializableTest { | ||||
/** | /** | ||||
classes.addAll(findServerClasses(location)); | classes.addAll(findServerClasses(location)); | ||||
} | } | ||||
ArrayList<Field> nonSerializableFunctionFields = new ArrayList<>(); | |||||
ArrayList<Class<?>> nonSerializableClasses = new ArrayList<>(); | ArrayList<Class<?>> nonSerializableClasses = new ArrayList<>(); | ||||
for (String className : classes) { | for (String className : classes) { | ||||
Class<?> cls = Class.forName(className); | 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 | // skip annotations and synthetic classes | ||||
if (cls.isAnnotation() || cls.isSynthetic()) { | if (cls.isAnnotation() || cls.isSynthetic()) { | ||||
continue; | 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 | // report non-serializable classes and interfaces | ||||
// useful failure message including all non-serializable classes and | // useful failure message including all non-serializable classes and | ||||
// interfaces | // interfaces | ||||
if (!nonSerializableClasses.isEmpty()) { | if (!nonSerializableClasses.isEmpty()) { | ||||
String nonSerializableString = ""; | |||||
Iterator<Class<?>> 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<Constructor<?>> 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<Field> 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<Class<?>> nonSerializableClasses) { | |||||
String nonSerializableString = ""; | |||||
Iterator<Class<?>> 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) { | private boolean isTestClass(Class<?> cls) { | ||||
* | * | ||||
* @return List of class path segment strings | * @return List of class path segment strings | ||||
*/ | */ | ||||
// | |||||
private final static List<String> getRawClasspathEntries() { | private final static List<String> getRawClasspathEntries() { | ||||
// try to keep the order of the classpath | // try to keep the order of the classpath | ||||
List<String> locations = new ArrayList<>(); | List<String> locations = new ArrayList<>(); |
import static org.junit.Assert.assertNull; | import static org.junit.Assert.assertNull; | ||||
import static org.junit.Assert.assertSame; | import static org.junit.Assert.assertSame; | ||||
import java.util.function.Function; | |||||
import org.junit.Before; | import org.junit.Before; | ||||
import org.junit.Test; | import org.junit.Test; | ||||
import com.vaadin.server.SerializableFunction; | |||||
import com.vaadin.ui.Grid; | import com.vaadin.ui.Grid; | ||||
import com.vaadin.ui.Grid.Column; | import com.vaadin.ui.Grid.Column; | ||||
import com.vaadin.ui.Grid.HeaderRow; | import com.vaadin.ui.Grid.HeaderRow; | ||||
public void setUp() { | public void setUp() { | ||||
grid = new Grid<>(); | 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 | @Test | ||||
public void initialState_updateColumnCaption_defaultHeaderUpdated() { | public void initialState_updateColumnCaption_defaultHeaderUpdated() { | ||||
column1.setCaption("1st"); | column1.setCaption("1st"); | ||||
assertEquals("1st", grid.getDefaultHeaderRow().getCell(column1) | |||||
.getText()); | |||||
assertEquals("1st", | |||||
grid.getDefaultHeaderRow().getCell(column1).getText()); | |||||
} | } | ||||
@Test | @Test | ||||
grid.setDefaultHeaderRow(grid.appendHeaderRow()); | grid.setDefaultHeaderRow(grid.appendHeaderRow()); | ||||
column1.setCaption("1st"); | 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()); | assertEquals("First", grid.getHeaderRow(0).getCell(column1).getText()); | ||||
} | } | ||||
grid.setDefaultHeaderRow(null); | grid.setDefaultHeaderRow(null); | ||||
column1.setCaption("1st"); | column1.setCaption("1st"); | ||||
assertEquals("First", grid.getHeaderRow(0).getCell(column1) | |||||
.getText()); | |||||
assertEquals("First", grid.getHeaderRow(0).getCell(column1).getText()); | |||||
} | } | ||||
} | } |
import static org.junit.Assert.assertSame; | import static org.junit.Assert.assertSame; | ||||
import static org.junit.Assert.fail; | import static org.junit.Assert.fail; | ||||
import java.util.function.Function; | |||||
import org.junit.Before; | import org.junit.Before; | ||||
import org.junit.Test; | import org.junit.Test; | ||||
import com.vaadin.server.SerializableFunction; | |||||
import com.vaadin.ui.Grid; | import com.vaadin.ui.Grid; | ||||
import com.vaadin.ui.Grid.Column; | import com.vaadin.ui.Grid.Column; | ||||
import com.vaadin.ui.Grid.HeaderRow; | import com.vaadin.ui.Grid.HeaderRow; | ||||
@Test | @Test | ||||
public void addColumn_headerCellAdded() { | public void addColumn_headerCellAdded() { | ||||
Column<?, ?> column = grid.addColumn("Col", Function.identity()); | |||||
Column<?, ?> column = grid.addColumn("Col", | |||||
SerializableFunction.identity()); | |||||
assertNotNull(grid.getHeaderRow(0).getCell(column)); | assertNotNull(grid.getHeaderRow(0).getCell(column)); | ||||
} | } | ||||
@Test(expected = IllegalArgumentException.class) | @Test(expected = IllegalArgumentException.class) | ||||
public void removeColumn_headerCellRemoved() { | public void removeColumn_headerCellRemoved() { | ||||
Column<String, ?> column = grid.addColumn("Col", Function.identity()); | |||||
Column<String, ?> column = grid.addColumn("Col", | |||||
SerializableFunction.identity()); | |||||
grid.removeColumn(column); | grid.removeColumn(column); | ||||
grid.getHeaderRow(0).getCell(column); | grid.getHeaderRow(0).getCell(column); |
import static org.junit.Assert.assertEquals; | import static org.junit.Assert.assertEquals; | ||||
import java.util.function.Function; | |||||
import org.junit.Before; | import org.junit.Before; | ||||
import org.junit.Test; | import org.junit.Test; | ||||
import com.vaadin.server.SerializableFunction; | |||||
import com.vaadin.shared.ui.grid.HeightMode; | import com.vaadin.shared.ui.grid.HeightMode; | ||||
import com.vaadin.ui.Grid; | import com.vaadin.ui.Grid; | ||||
import com.vaadin.ui.renderers.NumberRenderer; | import com.vaadin.ui.renderers.NumberRenderer; | ||||
@Before | @Before | ||||
public void setUp() { | public void setUp() { | ||||
grid = new Grid<>(); | grid = new Grid<>(); | ||||
grid.addColumn("foo", Function.identity()); | |||||
grid.addColumn("foo", SerializableFunction.identity()); | |||||
grid.addColumn(String::length, new NumberRenderer()); | grid.addColumn(String::length, new NumberRenderer()); | ||||
grid.addColumn("randomColumnId", Function.identity()); | |||||
grid.addColumn("randomColumnId", SerializableFunction.identity()); | |||||
} | } | ||||
@Test | @Test |
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.function.Function; | |||||
import com.vaadin.server.SerializableFunction; | |||||
import com.vaadin.server.VaadinRequest; | import com.vaadin.server.VaadinRequest; | ||||
import com.vaadin.server.data.DataSource; | import com.vaadin.server.data.DataSource; | ||||
import com.vaadin.tests.components.AbstractTestUI; | import com.vaadin.tests.components.AbstractTestUI; | ||||
protected void setup(VaadinRequest request) { | protected void setup(VaadinRequest request) { | ||||
Grid<String> grid = new Grid<>(); | Grid<String> grid = new Grid<>(); | ||||
grid.addColumn("Name", Function.identity()); | |||||
grid.addColumn("Name", SerializableFunction.identity()); | |||||
List<String> data = new ArrayList<>(); | List<String> data = new ArrayList<>(); | ||||
for (int i = 0; i < 1000; i++) { | for (int i = 0; i < 1000; i++) { |