/* * 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.data; import java.io.Serializable; import java.util.function.Function; import com.vaadin.data.Binder.BindingBuilder; import com.vaadin.server.SerializableFunction; /** * Interface that implements conversion between a model and a presentation type. * <p> * Converters must not have any side effects (never update UI from inside a * converter). * * @param <PRESENTATION> * The presentation type. * @param <MODEL> * The model type. * @author Vaadin Ltd. * @since 8.0 */ public interface Converter<PRESENTATION, MODEL> extends Serializable { /** * Converts the given value from model type to presentation type. * <p> * A converter can optionally use locale to do the conversion. * * @param value * The value to convert. Can be null * @param context * The value context for the conversion. * @return The converted value compatible with the source type */ public Result<MODEL> convertToModel(PRESENTATION value, ValueContext context); /** * Converts the given value from presentation type to model type. * <p> * A converter can optionally use locale to do the conversion. * * @param value * The value to convert. Can be null * @param context * The value context for the conversion. * @return The converted value compatible with the source type */ public PRESENTATION convertToPresentation(MODEL value, ValueContext context); /** * Returns a converter that returns its input as-is in both directions. * * @param <T> * the input and output type * @return an identity converter */ public static <T> Converter<T, T> identity() { return from(t -> Result.ok(t), t -> t); } /** * Constructs a converter from two functions. Any {@code Exception} * instances thrown from the {@code toModel} function are converted into * error-bearing {@code Result} objects using the given {@code onError} * function. * * @param <P> * the presentation type * @param <M> * the model type * @param toModel * the function to convert to model * @param toPresentation * the function to convert to presentation * @param onError * the function to provide error messages * @return the new converter * * @see Result * @see Function */ 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), toPresentation); } /** * Constructs a converter from a filter and a function. * * @param <P> * the presentation type * @param <M> * the model type * @param toModel * the function to convert to model * @param toPresentation * the function to convert to presentation * @return the new converter * * @see Function */ public static <P, M> Converter<P, M> from( SerializableFunction<P, Result<M>> toModel, SerializableFunction<M, P> toPresentation) { return new Converter<P, M>() { @Override public Result<M> convertToModel(P value, ValueContext context) { return toModel.apply(value); } @Override public P convertToPresentation(M value, ValueContext context) { return toPresentation.apply(value); } }; } /** * Returns a converter that chains together this converter with the given * type-compatible converter. * <p> * The chained converters will form a new converter capable of converting * from the presentation type of this converter to the model type of the * other converter. * <p> * In most typical cases you should not need this method but instead only * need to define one converter for a binding using * {@link BindingBuilder#withConverter(Converter)}. * * @param <T> * the model type of the resulting converter * @param other * the converter to chain, not null * @return a chained converter */ public default <T> Converter<PRESENTATION, T> chain( Converter<MODEL, T> other) { return new Converter<PRESENTATION, T>() { @Override public Result<T> convertToModel(PRESENTATION value, ValueContext context) { Result<MODEL> model = Converter.this.convertToModel(value, context); return model.flatMap(v -> other.convertToModel(v, context)); } @Override public PRESENTATION convertToPresentation(T value, ValueContext context) { MODEL model = other.convertToPresentation(value, context); return Converter.this.convertToPresentation(model, context); } }; } }