Browse Source

wip 2: revisited design

Still missing tests and example
pr/11306
Pekka 5 years ago
parent
commit
89c9bc96e5

+ 59
- 44
server/src/main/java/com/vaadin/data/Binder.java View File

@@ -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());
}

server/src/main/java/com/vaadin/data/BindingConverterFactory.java → server/src/main/java/com/vaadin/data/ConverterFactory.java View File

@@ -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);

}

server/src/main/java/com/vaadin/data/DefaultBindingConverterFactory.java → server/src/main/java/com/vaadin/data/DefaultConverterFactory.java View File

@@ -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

Loading…
Cancel
Save