diff options
-rw-r--r-- | server/src/main/java/com/vaadin/data/Binder.java | 103 | ||||
-rw-r--r-- | server/src/main/java/com/vaadin/data/ConverterFactory.java (renamed from server/src/main/java/com/vaadin/data/BindingConverterFactory.java) | 19 | ||||
-rw-r--r-- | server/src/main/java/com/vaadin/data/DefaultConverterFactory.java (renamed from server/src/main/java/com/vaadin/data/DefaultBindingConverterFactory.java) | 33 |
3 files changed, 91 insertions, 64 deletions
diff --git a/server/src/main/java/com/vaadin/data/Binder.java b/server/src/main/java/com/vaadin/data/Binder.java index 5393a8389c..af3c70e2d3 100644 --- a/server/src/main/java/com/vaadin/data/Binder.java +++ b/server/src/main/java/com/vaadin/data/Binder.java @@ -99,8 +99,8 @@ import com.vaadin.util.ReflectTools; */ public class Binder<BEAN> implements Serializable { - // TODO get default factory from session / ui like in V7 ? - private BindingConverterFactory defaultConverter; + private final DefaultConverterFactory defaultConverterFactory = new DefaultConverterFactory(); + private ConverterFactory customConverterFactory; /** * Represents the binding between a field and a data property. @@ -2639,28 +2639,26 @@ public class Binder<BEAN> implements Serializable { memberField.getName(), objectWithMemberFields.getClass().getName())); } + HasValue<?> field; + // Get the field from the object + try { + field = (HasValue<?>) ReflectTools.getJavaFieldValue( + objectWithMemberFields, memberField, HasValue.class); + } catch (IllegalArgumentException | IllegalAccessException + | InvocationTargetException e) { + // If we cannot determine the value, just skip the field + return false; + } + if (field == null) { + field = makeFieldInstance( + (Class<? extends HasValue<?>>) memberField.getType()); + initializeField(objectWithMemberFields, memberField, field); + } + BindingBuilder builder = forField(field); + Class<?> fieldClass = GenericTypeReflector.erase(valueType); - if (propertyType.equals(fieldClass) || (defaultConverter != null - && defaultConverter.isSupported(fieldClass, propertyType))) { - HasValue<?> field; - // Get the field from the object - try { - field = (HasValue<?>) ReflectTools.getJavaFieldValue( - objectWithMemberFields, memberField, HasValue.class); - } catch (IllegalArgumentException | IllegalAccessException - | InvocationTargetException e) { - // If we cannot determine the value, just skip the field - return false; - } - if (field == null) { - field = makeFieldInstance( - (Class<? extends HasValue<?>>) memberField.getType()); - initializeField(objectWithMemberFields, memberField, field); - } - BindingBuilder builder = forField(field); - if (defaultConverter != null) - builder = defaultConverter.buildBindingConverter(builder, fieldClass, - propertyType); + if (propertyType.equals(fieldClass) + || applyConverterFactory(builder, propertyType, fieldClass)) { builder.bind(property); return true; } else { @@ -2672,27 +2670,13 @@ public class Binder<BEAN> implements Serializable { } } - /** - * @return the current default binding converter - */ - public BindingConverterFactory getDefaultConverter() { - return defaultConverter; - } - - /** - * Set at default binding converter. If this is set, it is used when - * {@link #bindInstanceFields(Object)} is called. The default converter is - * able to convert a set of input classes to a given range of output - * classes. This is typically used for automatically binding Integer, - * Double, Long or Float to a TextField (which use String as a return - * value). It may also be used to convert {@link java.time.LocalDateTime} - * (or LocalDate) to the old {@link java.util.Date} - * - * @param defaultConverter - * an interface for converting values - */ - public void setDefaultConverter(DefaultBindingConverterFactory defaultConverter) { - this.defaultConverter = defaultConverter; + private boolean applyConverterFactory(BindingBuilder bindingBuilder, + Class<?> modelType, Class<?> presentationType) { + return customConverterFactory != null + && customConverterFactory.applyConverter(bindingBuilder, + presentationType, modelType) + || getDefaultConverterFactory().applyConverter(bindingBuilder, + presentationType, modelType); } /** @@ -2923,6 +2907,37 @@ public class Binder<BEAN> implements Serializable { .ifPresent(Binding::unbind); } + /** + * TODO + * + * @return + * @since + */ + public ConverterFactory getCustomConverterFactory() { + return customConverterFactory; + } + + /** + * TODO + * + * @param customConverterFactory + * @since + */ + public void setCustomConverterFactory( + ConverterFactory customConverterFactory) { + this.customConverterFactory = customConverterFactory; + } + + /** + * TODO + * + * @return + * @since + */ + public DefaultConverterFactory getDefaultConverterFactory() { + return defaultConverterFactory; + } + private static final Logger getLogger() { return Logger.getLogger(Binder.class.getName()); } diff --git a/server/src/main/java/com/vaadin/data/BindingConverterFactory.java b/server/src/main/java/com/vaadin/data/ConverterFactory.java index 1cd78a4fef..c3ac4cd7f9 100644 --- a/server/src/main/java/com/vaadin/data/BindingConverterFactory.java +++ b/server/src/main/java/com/vaadin/data/ConverterFactory.java @@ -23,12 +23,20 @@ import java.io.Serializable; * Binder when creating bindings with {@link Binder#bindInstanceFields(Object)}. * <p> * The framework default implementation is - * {@link DefaultBindingConverterFactory}. + * {@link DefaultConverterFactory}. * * @author Vaadin Ltd. * @since */ -public interface BindingConverterFactory extends Serializable { +public interface ConverterFactory extends Serializable { + + <PRESENTATION, MODEL> boolean applyConverter( + Binder.BindingBuilder<MODEL, PRESENTATION> bindingBuilder, + Class<PRESENTATION> presentationType, Class<MODEL> modelType); + +// <MODEL, PRESENTATION> Optional<Consumer<Binder.BindingBuilder<MODEL, +// PRESENTATION>>> getConverterApplier( +// Class<PRESENTATION> presentationType, Class<MODEL> modelType); /** * Builds converter to the given binding to convert between the presentation @@ -43,8 +51,9 @@ public interface BindingConverterFactory extends Serializable { * the bean property type * @return the binder builder with converter applied if possible */ - Binder.BindingBuilder buildBindingConverter(Binder.BindingBuilder builder, - Class<?> presentationType, Class<?> modelType); + // Binder.BindingBuilder buildBindingConverter(Binder.BindingBuilder + // builder, + // Class<?> presentationType, Class<?> modelType); /** * Returns whether this factory has a converter to convert between the @@ -57,6 +66,6 @@ public interface BindingConverterFactory extends Serializable { * class of the property type in the entity * @return {@code true} if conversion possible, {@code false} if not */ - boolean isSupported(Class<?> presentationType, Class<?> modelType); + // boolean isSupported(Class<?> presentationType, Class<?> modelType); } diff --git a/server/src/main/java/com/vaadin/data/DefaultBindingConverterFactory.java b/server/src/main/java/com/vaadin/data/DefaultConverterFactory.java index d7aae39b8a..1b7efcd47f 100644 --- a/server/src/main/java/com/vaadin/data/DefaultBindingConverterFactory.java +++ b/server/src/main/java/com/vaadin/data/DefaultConverterFactory.java @@ -45,7 +45,7 @@ import com.vaadin.server.SerializableFunction; /** * TODO */ -public class DefaultBindingConverterFactory implements BindingConverterFactory { +public class DefaultConverterFactory implements ConverterFactory { private static final Map<Class<?>, Set<Class<?>>> SUPPORTED_PRESENTATION_TO_MODEL_CONVERTERS_MAP = new HashMap<>(); static { @@ -60,6 +60,8 @@ public class DefaultBindingConverterFactory implements BindingConverterFactory { new HashSet<>(Collections.singletonList(Date.class))); } + // TODO: provide setters for customizing default behavior + private static final SerializableFunction<Class, ErrorMessageProvider> TYPE_BASED_ERROR_MESSAGE_PROVIDER = clazz -> context -> String .format("Invalid value, expected ${0}", clazz.getSimpleName()); @@ -68,34 +70,36 @@ public class DefaultBindingConverterFactory implements BindingConverterFactory { } @Override - public Binder.BindingBuilder buildBindingConverter( - Binder.BindingBuilder builder, Class<?> presentationType, - Class<?> modelType) { + public <PRESENTATION, MODEL> boolean applyConverter( + Binder.BindingBuilder<MODEL, PRESENTATION> builder, + Class<PRESENTATION> presentationType, Class<MODEL> modelType) { if (isSupported(presentationType, modelType)) { - Supplier<?> nullRepresentationProvider = getNullRepresentationProvider( + Supplier<PRESENTATION> nullRepresentationProvider = getNullRepresentationProvider( presentationType, modelType); if (nullRepresentationProvider != null) { - builder = builder.withNullRepresentation( + builder.withNullRepresentation( nullRepresentationProvider.get()); } if (presentationType == String.class) { - builder = builder + ((Binder.BindingBuilder<MODEL, String>)builder) .withConverter(createStringConverter(modelType)); } else if (presentationType == LocalDateTime.class) { if (modelType == Date.class) { - builder = builder + ((Binder.BindingBuilder<Date, LocalDateTime>)builder) .withConverter(new LocalDateTimeToDateConverter( getZoneIdForDateConverters())); } } else if (presentationType == LocalDate.class) { if (modelType == Date.class) { - builder = builder + ((Binder.BindingBuilder<Date, LocalDate>)builder) .withConverter(new LocalDateToDateConverter( getZoneIdForDateConverters())); } } + return true; + } else { + return false; } - return builder; } /** @@ -147,10 +151,10 @@ public class DefaultBindingConverterFactory implements BindingConverterFactory { * @return the null representation provider, or {@code null} to prevent * conversion of {@code null} model value */ - protected Supplier<?> getNullRepresentationProvider( - Class<?> presentationType, Class<?> modelType) { + protected <PRESENTATION> Supplier<PRESENTATION> getNullRepresentationProvider( + Class<PRESENTATION> presentationType, Class<?> modelType) { if (presentationType.equals(String.class)) { - return () -> ""; + return () -> (PRESENTATION) ""; } return null; } @@ -172,8 +176,7 @@ public class DefaultBindingConverterFactory implements BindingConverterFactory { return ZoneId.systemDefault(); } - @Override - public boolean isSupported(Class<?> presentationType, Class<?> modelType) { + private boolean isSupported(Class<?> presentationType, Class<?> modelType) { Set<Class<?>> supported = SUPPORTED_PRESENTATION_TO_MODEL_CONVERTERS_MAP .get(presentationType); return supported != null && supported.size() > 0 |