BindingBinder is API that is used before calling bind() Binding is API that is used after calling bind()tags/8.0.0.alpha9
@@ -66,74 +66,76 @@ public class BeanBinder<BEAN> extends Binder<BEAN> { | |||
* @param <TARGET> | |||
* the target property type | |||
*/ | |||
public interface BeanBinding<BEAN, TARGET> extends Binding<BEAN, TARGET> { | |||
public interface BeanBindingBuilder<BEAN, TARGET> | |||
extends BindingBuilder<BEAN, TARGET> { | |||
@Override | |||
public BeanBinding<BEAN, TARGET> withValidator( | |||
public BeanBindingBuilder<BEAN, TARGET> withValidator( | |||
Validator<? super TARGET> validator); | |||
@Override | |||
public default BeanBinding<BEAN, TARGET> withValidator( | |||
public default BeanBindingBuilder<BEAN, TARGET> withValidator( | |||
SerializablePredicate<? super TARGET> predicate, | |||
String message) { | |||
return (BeanBinding<BEAN, TARGET>) Binding.super.withValidator( | |||
return (BeanBindingBuilder<BEAN, TARGET>) BindingBuilder.super.withValidator( | |||
predicate, message); | |||
} | |||
@Override | |||
default BeanBinding<BEAN, TARGET> withValidator( | |||
default BeanBindingBuilder<BEAN, TARGET> withValidator( | |||
SerializablePredicate<? super TARGET> predicate, | |||
ErrorMessageProvider errorMessageProvider) { | |||
return (BeanBinding<BEAN, TARGET>) Binding.super.withValidator( | |||
return (BeanBindingBuilder<BEAN, TARGET>) BindingBuilder.super.withValidator( | |||
predicate, errorMessageProvider); | |||
} | |||
@Override | |||
default BeanBinding<BEAN, TARGET> withNullRepresentation( | |||
default BeanBindingBuilder<BEAN, TARGET> withNullRepresentation( | |||
TARGET nullRepresentation) { | |||
return (BeanBinding<BEAN, TARGET>) Binding.super.withNullRepresentation( | |||
return (BeanBindingBuilder<BEAN, TARGET>) BindingBuilder.super.withNullRepresentation( | |||
nullRepresentation); | |||
} | |||
@Override | |||
public BeanBinding<BEAN, TARGET> setRequired( | |||
public BeanBindingBuilder<BEAN, TARGET> setRequired( | |||
ErrorMessageProvider errorMessageProvider); | |||
@Override | |||
public default BeanBinding<BEAN, TARGET> setRequired( | |||
public default BeanBindingBuilder<BEAN, TARGET> setRequired( | |||
String errorMessage) { | |||
return (BeanBinding<BEAN, TARGET>) Binding.super.setRequired( | |||
return (BeanBindingBuilder<BEAN, TARGET>) BindingBuilder.super.setRequired( | |||
errorMessage); | |||
} | |||
@Override | |||
public <NEWTARGET> BeanBinding<BEAN, NEWTARGET> withConverter( | |||
public <NEWTARGET> BeanBindingBuilder<BEAN, NEWTARGET> withConverter( | |||
Converter<TARGET, NEWTARGET> converter); | |||
@Override | |||
public default <NEWTARGET> BeanBinding<BEAN, NEWTARGET> withConverter( | |||
public default <NEWTARGET> BeanBindingBuilder<BEAN, NEWTARGET> withConverter( | |||
SerializableFunction<TARGET, NEWTARGET> toModel, | |||
SerializableFunction<NEWTARGET, TARGET> toPresentation) { | |||
return (BeanBinding<BEAN, NEWTARGET>) Binding.super.withConverter( | |||
return (BeanBindingBuilder<BEAN, NEWTARGET>) BindingBuilder.super.withConverter( | |||
toModel, toPresentation); | |||
} | |||
@Override | |||
public default <NEWTARGET> BeanBinding<BEAN, NEWTARGET> withConverter( | |||
public default <NEWTARGET> BeanBindingBuilder<BEAN, NEWTARGET> withConverter( | |||
SerializableFunction<TARGET, NEWTARGET> toModel, | |||
SerializableFunction<NEWTARGET, TARGET> toPresentation, | |||
String errorMessage) { | |||
return (BeanBinding<BEAN, NEWTARGET>) Binding.super.withConverter( | |||
return (BeanBindingBuilder<BEAN, NEWTARGET>) BindingBuilder.super.withConverter( | |||
toModel, toPresentation, errorMessage); | |||
} | |||
@Override | |||
public BeanBinding<BEAN, TARGET> withValidationStatusHandler( | |||
public BeanBindingBuilder<BEAN, TARGET> withValidationStatusHandler( | |||
ValidationStatusHandler handler); | |||
@Override | |||
public default BeanBinding<BEAN, TARGET> withStatusLabel(Label label) { | |||
return (BeanBinding<BEAN, TARGET>) Binding.super.withStatusLabel( | |||
public default BeanBindingBuilder<BEAN, TARGET> withStatusLabel( | |||
Label label) { | |||
return (BeanBindingBuilder<BEAN, TARGET>) BindingBuilder.super.withStatusLabel( | |||
label); | |||
} | |||
@@ -152,19 +154,21 @@ public class BeanBinder<BEAN> extends Binder<BEAN> { | |||
* | |||
* @param propertyName | |||
* the name of the property to bind, not null | |||
* @return the newly created binding | |||
* | |||
* @throws IllegalArgumentException | |||
* if the property name is invalid | |||
* @throws IllegalArgumentException | |||
* if the property has no accessible getter | |||
* | |||
* @see Binding#bind(SerializableFunction, SerializableBiConsumer) | |||
* @see BindingBuilder#bind(SerializableFunction, | |||
* SerializableBiConsumer) | |||
*/ | |||
public void bind(String propertyName); | |||
public Binding<BEAN, TARGET> bind(String propertyName); | |||
} | |||
/** | |||
* An internal implementation of {@link BeanBinding}. | |||
* An internal implementation of {@link BeanBindingBuilder}. | |||
* | |||
* @param <BEAN> | |||
* the bean type | |||
@@ -174,11 +178,8 @@ public class BeanBinder<BEAN> extends Binder<BEAN> { | |||
* the target property type | |||
*/ | |||
protected static class BeanBindingImpl<BEAN, FIELDVALUE, TARGET> | |||
extends BindingImpl<BEAN, FIELDVALUE, TARGET> | |||
implements BeanBinding<BEAN, TARGET> { | |||
private Method getter; | |||
private Method setter; | |||
extends BindingBuilderImpl<BEAN, FIELDVALUE, TARGET> | |||
implements BeanBindingBuilder<BEAN, TARGET> { | |||
/** | |||
* Creates a new bean binding. | |||
@@ -200,50 +201,60 @@ public class BeanBinder<BEAN> extends Binder<BEAN> { | |||
} | |||
@Override | |||
public BeanBinding<BEAN, TARGET> withValidator( | |||
public BeanBindingBuilder<BEAN, TARGET> withValidator( | |||
Validator<? super TARGET> validator) { | |||
return (BeanBinding<BEAN, TARGET>) super.withValidator(validator); | |||
return (BeanBindingBuilder<BEAN, TARGET>) super.withValidator( | |||
validator); | |||
} | |||
@Override | |||
public <NEWTARGET> BeanBinding<BEAN, NEWTARGET> withConverter( | |||
public <NEWTARGET> BeanBindingBuilder<BEAN, NEWTARGET> withConverter( | |||
Converter<TARGET, NEWTARGET> converter) { | |||
return (BeanBinding<BEAN, NEWTARGET>) super.withConverter( | |||
return (BeanBindingBuilder<BEAN, NEWTARGET>) super.withConverter( | |||
converter); | |||
} | |||
@Override | |||
public BeanBinding<BEAN, TARGET> withValidationStatusHandler( | |||
public BeanBindingBuilder<BEAN, TARGET> withValidationStatusHandler( | |||
ValidationStatusHandler handler) { | |||
return (BeanBinding<BEAN, TARGET>) super.withValidationStatusHandler( | |||
return (BeanBindingBuilder<BEAN, TARGET>) super.withValidationStatusHandler( | |||
handler); | |||
} | |||
@Override | |||
public BeanBinding<BEAN, TARGET> setRequired( | |||
public BeanBindingBuilder<BEAN, TARGET> setRequired( | |||
ErrorMessageProvider errorMessageProvider) { | |||
return (BeanBinding<BEAN, TARGET>) super.setRequired( | |||
return (BeanBindingBuilder<BEAN, TARGET>) super.setRequired( | |||
errorMessageProvider); | |||
} | |||
@Override | |||
public void bind(String propertyName) { | |||
public Binding<BEAN, TARGET> bind(String propertyName) { | |||
checkUnbound(); | |||
Binding<BEAN, Object> finalBinding; | |||
BindingBuilder<BEAN, Object> finalBinding; | |||
PropertyDescriptor descriptor = getDescriptor(propertyName); | |||
Method getter = descriptor.getReadMethod(); | |||
Method setter = descriptor.getWriteMethod(); | |||
finalBinding = withConverter(createConverter(), false); | |||
finalBinding = withConverter( | |||
createConverter(getter.getReturnType()), false); | |||
if (BeanUtil.checkBeanValidationAvailable()) { | |||
finalBinding = finalBinding.withValidator( | |||
new BeanValidator(getBinder().beanType, propertyName)); | |||
} | |||
PropertyDescriptor descriptor = getDescriptor(propertyName); | |||
getter = descriptor.getReadMethod(); | |||
setter = descriptor.getWriteMethod(); | |||
finalBinding.bind(this::getValue, this::setValue); | |||
getBinder().boundProperties.add(propertyName); | |||
try { | |||
return (Binding<BEAN, TARGET>) finalBinding.bind( | |||
bean -> invokeWrapExceptions(getter, bean), | |||
(bean, value) -> invokeWrapExceptions(setter, bean, | |||
value)); | |||
} finally { | |||
getBinder().boundProperties.add(propertyName); | |||
} | |||
} | |||
@Override | |||
@@ -251,19 +262,13 @@ public class BeanBinder<BEAN> extends Binder<BEAN> { | |||
return (BeanBinder<BEAN>) super.getBinder(); | |||
} | |||
private void setValue(BEAN bean, Object value) { | |||
try { | |||
if (setter != null) { | |||
setter.invoke(bean, value); | |||
} | |||
} catch (IllegalAccessException | InvocationTargetException e) { | |||
throw new RuntimeException(e); | |||
private static Object invokeWrapExceptions(Method method, Object target, | |||
Object... parameters) { | |||
if (method == null) { | |||
return null; | |||
} | |||
} | |||
private Object getValue(BEAN bean) { | |||
try { | |||
return getter.invoke(bean); | |||
return method.invoke(target, parameters); | |||
} catch (IllegalAccessException | InvocationTargetException e) { | |||
throw new RuntimeException(e); | |||
} | |||
@@ -295,9 +300,8 @@ public class BeanBinder<BEAN> extends Binder<BEAN> { | |||
} | |||
@SuppressWarnings("unchecked") | |||
private Converter<TARGET, Object> createConverter() { | |||
return Converter.from( | |||
fieldValue -> cast(fieldValue, getter.getReturnType()), | |||
private Converter<TARGET, Object> createConverter(Class<?> getterType) { | |||
return Converter.from(fieldValue -> cast(fieldValue, getterType), | |||
propertyValue -> (TARGET) propertyValue, exception -> { | |||
throw new RuntimeException(exception); | |||
}); | |||
@@ -328,9 +332,9 @@ public class BeanBinder<BEAN> extends Binder<BEAN> { | |||
} | |||
@Override | |||
public <FIELDVALUE> BeanBinding<BEAN, FIELDVALUE> forField( | |||
public <FIELDVALUE> BeanBindingBuilder<BEAN, FIELDVALUE> forField( | |||
HasValue<FIELDVALUE> field) { | |||
return (BeanBinding<BEAN, FIELDVALUE>) super.forField(field); | |||
return (BeanBindingBuilder<BEAN, FIELDVALUE>) super.forField(field); | |||
} | |||
/** | |||
@@ -351,6 +355,7 @@ public class BeanBinder<BEAN> extends Binder<BEAN> { | |||
* the field to bind, not null | |||
* @param propertyName | |||
* the name of the property to bind, not null | |||
* @return the newly created binding | |||
* | |||
* @throws IllegalArgumentException | |||
* if the property name is invalid | |||
@@ -359,9 +364,9 @@ public class BeanBinder<BEAN> extends Binder<BEAN> { | |||
* | |||
* @see #bind(HasValue, SerializableFunction, SerializableBiConsumer) | |||
*/ | |||
public <FIELDVALUE> void bind(HasValue<FIELDVALUE> field, | |||
String propertyName) { | |||
forField(field).bind(propertyName); | |||
public <FIELDVALUE> Binding<BEAN, FIELDVALUE> bind( | |||
HasValue<FIELDVALUE> field, String propertyName) { | |||
return forField(field).bind(propertyName); | |||
} | |||
@Override |
@@ -42,7 +42,6 @@ import com.vaadin.server.SerializablePredicate; | |||
import com.vaadin.server.UserError; | |||
import com.vaadin.shared.Registration; | |||
import com.vaadin.ui.AbstractComponent; | |||
import com.vaadin.ui.AbstractMultiSelect; | |||
import com.vaadin.ui.Component; | |||
import com.vaadin.ui.Label; | |||
import com.vaadin.ui.UI; | |||
@@ -80,6 +79,7 @@ import com.vaadin.ui.UI; | |||
* @param <BEAN> | |||
* the bean type | |||
* | |||
* @see BindingBuilder | |||
* @see Binding | |||
* @see HasValue | |||
* | |||
@@ -94,12 +94,45 @@ public class Binder<BEAN> implements Serializable { | |||
* the bean type | |||
* @param <TARGET> | |||
* the target data type of the binding, matches the field type | |||
* until a converter has been set | |||
* unless a converter has been set | |||
* | |||
* @see Binder#forField(HasValue) | |||
*/ | |||
public interface Binding<BEAN, TARGET> extends Serializable { | |||
/** | |||
* Gets the field the binding uses. | |||
* | |||
* @return the field for the binding | |||
*/ | |||
public HasValue<?> getField(); | |||
/** | |||
* Validates the field value and returns a {@code ValidationStatus} | |||
* instance representing the outcome of the validation. | |||
* | |||
* @see Binder#validate() | |||
* @see Validator#apply(Object) | |||
* | |||
* @return the validation result. | |||
*/ | |||
public ValidationStatus<TARGET> validate(); | |||
} | |||
/** | |||
* Creates a binding between a field and a data property. | |||
* | |||
* @param <BEAN> | |||
* the bean type | |||
* @param <TARGET> | |||
* the target data type of the binding, matches the field type | |||
* until a converter has been set | |||
* | |||
* @see Binder#forField(HasValue) | |||
*/ | |||
public interface BindingBuilder<BEAN, TARGET> extends Serializable { | |||
/** | |||
* Completes this binding using the given getter and setter functions | |||
* representing a backing bean property. The functions are used to | |||
@@ -136,10 +169,12 @@ public class Binder<BEAN> implements Serializable { | |||
* @param setter | |||
* the function to write the field value to the property or | |||
* null if read-only | |||
* @return the newly created binding | |||
* @throws IllegalStateException | |||
* if {@code bind} has already been called on this binding | |||
*/ | |||
public void bind(SerializableFunction<BEAN, TARGET> getter, | |||
public Binding<BEAN, TARGET> bind( | |||
SerializableFunction<BEAN, TARGET> getter, | |||
com.vaadin.server.SerializableBiConsumer<BEAN, TARGET> setter); | |||
/** | |||
@@ -157,7 +192,7 @@ public class Binder<BEAN> implements Serializable { | |||
* @throws IllegalStateException | |||
* if {@code bind} has already been called | |||
*/ | |||
public Binding<BEAN, TARGET> withValidator( | |||
public BindingBuilder<BEAN, TARGET> withValidator( | |||
Validator<? super TARGET> validator); | |||
/** | |||
@@ -180,7 +215,7 @@ public class Binder<BEAN> implements Serializable { | |||
* @throws IllegalStateException | |||
* if {@code bind} has already been called | |||
*/ | |||
public default Binding<BEAN, TARGET> withValidator( | |||
public default BindingBuilder<BEAN, TARGET> withValidator( | |||
SerializablePredicate<? super TARGET> predicate, | |||
String message) { | |||
return withValidator(Validator.from(predicate, message)); | |||
@@ -207,7 +242,7 @@ public class Binder<BEAN> implements Serializable { | |||
* @throws IllegalStateException | |||
* if {@code bind} has already been called | |||
*/ | |||
public default Binding<BEAN, TARGET> withValidator( | |||
public default BindingBuilder<BEAN, TARGET> withValidator( | |||
SerializablePredicate<? super TARGET> predicate, | |||
ErrorMessageProvider errorMessageProvider) { | |||
return withValidator( | |||
@@ -237,7 +272,7 @@ public class Binder<BEAN> implements Serializable { | |||
* @throws IllegalStateException | |||
* if {@code bind} has already been called | |||
*/ | |||
public <NEWTARGET> Binding<BEAN, NEWTARGET> withConverter( | |||
public <NEWTARGET> BindingBuilder<BEAN, NEWTARGET> withConverter( | |||
Converter<TARGET, NEWTARGET> converter); | |||
/** | |||
@@ -267,7 +302,7 @@ public class Binder<BEAN> implements Serializable { | |||
* @throws IllegalStateException | |||
* if {@code bind} has already been called | |||
*/ | |||
public default <NEWTARGET> Binding<BEAN, NEWTARGET> withConverter( | |||
public default <NEWTARGET> BindingBuilder<BEAN, NEWTARGET> withConverter( | |||
SerializableFunction<TARGET, NEWTARGET> toModel, | |||
SerializableFunction<NEWTARGET, TARGET> toPresentation) { | |||
return withConverter(Converter.from(toModel, toPresentation, | |||
@@ -305,7 +340,7 @@ public class Binder<BEAN> implements Serializable { | |||
* @throws IllegalStateException | |||
* if {@code bind} has already been called | |||
*/ | |||
public default <NEWTARGET> Binding<BEAN, NEWTARGET> withConverter( | |||
public default <NEWTARGET> BindingBuilder<BEAN, NEWTARGET> withConverter( | |||
SerializableFunction<TARGET, NEWTARGET> toModel, | |||
SerializableFunction<NEWTARGET, TARGET> toPresentation, | |||
String errorMessage) { | |||
@@ -321,7 +356,7 @@ public class Binder<BEAN> implements Serializable { | |||
* the value to use instead of {@code null} | |||
* @return a new binding with null representation handling. | |||
*/ | |||
public default Binding<BEAN, TARGET> withNullRepresentation( | |||
public default BindingBuilder<BEAN, TARGET> withNullRepresentation( | |||
TARGET nullRepresentation) { | |||
return withConverter( | |||
fieldValue -> Objects.equals(fieldValue, nullRepresentation) | |||
@@ -330,13 +365,6 @@ public class Binder<BEAN> implements Serializable { | |||
? nullRepresentation : modelValue); | |||
} | |||
/** | |||
* Gets the field the binding uses. | |||
* | |||
* @return the field for the binding | |||
*/ | |||
public HasValue<?> getField(); | |||
/** | |||
* Sets the given {@code label} to show an error message if validation | |||
* fails. | |||
@@ -369,7 +397,8 @@ public class Binder<BEAN> implements Serializable { | |||
* label to show validation status for the field | |||
* @return this binding, for chaining | |||
*/ | |||
public default Binding<BEAN, TARGET> withStatusLabel(Label label) { | |||
public default BindingBuilder<BEAN, TARGET> withStatusLabel( | |||
Label label) { | |||
return withValidationStatusHandler(status -> { | |||
label.setValue(status.getMessage().orElse("")); | |||
// Only show the label when validation has failed | |||
@@ -406,20 +435,9 @@ public class Binder<BEAN> implements Serializable { | |||
* status change handler | |||
* @return this binding, for chaining | |||
*/ | |||
public Binding<BEAN, TARGET> withValidationStatusHandler( | |||
public BindingBuilder<BEAN, TARGET> withValidationStatusHandler( | |||
ValidationStatusHandler handler); | |||
/** | |||
* Validates the field value and returns a {@code ValidationStatus} | |||
* instance representing the outcome of the validation. | |||
* | |||
* @see Binder#validate() | |||
* @see Validator#apply(Object) | |||
* | |||
* @return the validation result. | |||
*/ | |||
public ValidationStatus<TARGET> validate(); | |||
/** | |||
* Sets the field to be required. This means two things: | |||
* <ol> | |||
@@ -439,7 +457,8 @@ public class Binder<BEAN> implements Serializable { | |||
* the error message to show for the invalid value | |||
* @return this binding, for chaining | |||
*/ | |||
public default Binding<BEAN, TARGET> setRequired(String errorMessage) { | |||
public default BindingBuilder<BEAN, TARGET> setRequired( | |||
String errorMessage) { | |||
return setRequired(context -> errorMessage); | |||
} | |||
@@ -458,12 +477,12 @@ public class Binder<BEAN> implements Serializable { | |||
* the provider for localized validation error message | |||
* @return this binding, for chaining | |||
*/ | |||
public Binding<BEAN, TARGET> setRequired( | |||
public BindingBuilder<BEAN, TARGET> setRequired( | |||
ErrorMessageProvider errorMessageProvider); | |||
} | |||
/** | |||
* An internal implementation of {@code Binding}. | |||
* An internal implementation of {@code BindingBuilder}. | |||
* | |||
* @param <BEAN> | |||
* the bean type, must match the Binder bean type | |||
@@ -473,18 +492,16 @@ public class Binder<BEAN> implements Serializable { | |||
* the target data type of the binding, matches the field type | |||
* until a converter has been set | |||
*/ | |||
protected static class BindingImpl<BEAN, FIELDVALUE, TARGET> | |||
implements Binding<BEAN, TARGET> { | |||
protected static class BindingBuilderImpl<BEAN, FIELDVALUE, TARGET> | |||
implements BindingBuilder<BEAN, TARGET> { | |||
private final Binder<BEAN> binder; | |||
private final HasValue<FIELDVALUE> field; | |||
private Registration onValueChange; | |||
private ValidationStatusHandler statusHandler; | |||
private boolean isStatusHandlerChanged; | |||
private SerializableFunction<BEAN, TARGET> getter; | |||
private SerializableBiConsumer<BEAN, TARGET> setter; | |||
private boolean bound; | |||
/** | |||
* Contains all converters and validators chained together in the | |||
@@ -493,8 +510,9 @@ public class Binder<BEAN> implements Serializable { | |||
private Converter<FIELDVALUE, TARGET> converterValidatorChain; | |||
/** | |||
* Creates a new binding associated with the given field. Initializes | |||
* the binding with the given converter chain and status change handler. | |||
* Creates a new binding builder associated with the given field. | |||
* Initializes the builder with the given converter chain and status | |||
* change handler. | |||
* | |||
* @param binder | |||
* the binder this instance is connected to, not null | |||
@@ -505,7 +523,8 @@ public class Binder<BEAN> implements Serializable { | |||
* @param statusHandler | |||
* the handler to track validation status, not null | |||
*/ | |||
protected BindingImpl(Binder<BEAN> binder, HasValue<FIELDVALUE> field, | |||
protected BindingBuilderImpl(Binder<BEAN> binder, | |||
HasValue<FIELDVALUE> field, | |||
Converter<FIELDVALUE, TARGET> converterValidatorChain, | |||
ValidationStatusHandler statusHandler) { | |||
this.field = field; | |||
@@ -515,22 +534,26 @@ public class Binder<BEAN> implements Serializable { | |||
} | |||
@Override | |||
public void bind(SerializableFunction<BEAN, TARGET> getter, | |||
public Binding<BEAN, TARGET> bind( | |||
SerializableFunction<BEAN, TARGET> getter, | |||
SerializableBiConsumer<BEAN, TARGET> setter) { | |||
checkUnbound(); | |||
Objects.requireNonNull(getter, "getter cannot be null"); | |||
this.getter = getter; | |||
this.setter = setter; | |||
onValueChange = getField() | |||
.addValueChangeListener(this::handleFieldValueChange); | |||
getBinder().bindings.add(this); | |||
getBinder().getBean().ifPresent(this::initFieldValue); | |||
BindingImpl<BEAN, FIELDVALUE, TARGET> binding = new BindingImpl<>( | |||
this, getter, setter); | |||
getBinder().bindings.add(binding); | |||
getBinder().getBean().ifPresent(binding::initFieldValue); | |||
getBinder().fireStatusChangeEvent(false); | |||
bound = true; | |||
return binding; | |||
} | |||
@Override | |||
public Binding<BEAN, TARGET> withValidator( | |||
public BindingBuilder<BEAN, TARGET> withValidator( | |||
Validator<? super TARGET> validator) { | |||
checkUnbound(); | |||
Objects.requireNonNull(validator, "validator cannot be null"); | |||
@@ -541,13 +564,13 @@ public class Binder<BEAN> implements Serializable { | |||
} | |||
@Override | |||
public <NEWTARGET> Binding<BEAN, NEWTARGET> withConverter( | |||
public <NEWTARGET> BindingBuilder<BEAN, NEWTARGET> withConverter( | |||
Converter<TARGET, NEWTARGET> converter) { | |||
return withConverter(converter, true); | |||
} | |||
@Override | |||
public Binding<BEAN, TARGET> withValidationStatusHandler( | |||
public BindingBuilder<BEAN, TARGET> withValidationStatusHandler( | |||
ValidationStatusHandler handler) { | |||
checkUnbound(); | |||
Objects.requireNonNull(handler, "handler cannot be null"); | |||
@@ -562,21 +585,15 @@ public class Binder<BEAN> implements Serializable { | |||
} | |||
@Override | |||
public Binding<BEAN, TARGET> setRequired( | |||
public BindingBuilder<BEAN, TARGET> setRequired( | |||
ErrorMessageProvider errorMessageProvider) { | |||
checkUnbound(); | |||
getField().setRequiredIndicatorVisible(true); | |||
field.setRequiredIndicatorVisible(true); | |||
return withValidator( | |||
value -> !Objects.equals(value, getField().getEmptyValue()), | |||
value -> !Objects.equals(value, field.getEmptyValue()), | |||
errorMessageProvider); | |||
} | |||
@Override | |||
public HasValue<FIELDVALUE> getField() { | |||
return field; | |||
} | |||
/** | |||
* Implements {@link #withConverter(Converter)} method with additional | |||
* possibility to disable (reset) default null representation converter. | |||
@@ -597,17 +614,17 @@ public class Binder<BEAN> implements Serializable { | |||
* @throws IllegalStateException | |||
* if {@code bind} has already been called | |||
*/ | |||
protected <NEWTARGET> Binding<BEAN, NEWTARGET> withConverter( | |||
protected <NEWTARGET> BindingBuilder<BEAN, NEWTARGET> withConverter( | |||
Converter<TARGET, NEWTARGET> converter, | |||
boolean resetNullRepresentation) { | |||
checkUnbound(); | |||
Objects.requireNonNull(converter, "converter cannot be null"); | |||
if (resetNullRepresentation) { | |||
getBinder().initialConverters.get(getField()).setIdentity(); | |||
getBinder().initialConverters.get(field).setIdentity(); | |||
} | |||
return getBinder().createBinding(getField(), | |||
return getBinder().createBinding(field, | |||
converterValidatorChain.chain(converter), statusHandler); | |||
} | |||
@@ -629,11 +646,63 @@ public class Binder<BEAN> implements Serializable { | |||
* if this binding is already bound | |||
*/ | |||
protected void checkUnbound() { | |||
if (getter != null) { | |||
if (bound) { | |||
throw new IllegalStateException( | |||
"cannot modify binding: already bound to a property"); | |||
} | |||
} | |||
} | |||
/** | |||
* An internal implementation of {@code Binding}. | |||
* | |||
* @param <BEAN> | |||
* the bean type, must match the Binder bean type | |||
* @param <FIELDVALUE> | |||
* the value type of the field | |||
* @param <TARGET> | |||
* the target data type of the binding, matches the field type | |||
* unless a converter has been set | |||
*/ | |||
protected static class BindingImpl<BEAN, FIELDVALUE, TARGET> | |||
implements Binding<BEAN, TARGET> { | |||
private final Binder<BEAN> binder; | |||
private final HasValue<FIELDVALUE> field; | |||
private final ValidationStatusHandler statusHandler; | |||
private final SerializableFunction<BEAN, TARGET> getter; | |||
private final SerializableBiConsumer<BEAN, TARGET> setter; | |||
// Not final since we temporarily remove listener while changing values | |||
private Registration onValueChange; | |||
/** | |||
* Contains all converters and validators chained together in the | |||
* correct order. | |||
*/ | |||
private final Converter<FIELDVALUE, TARGET> converterValidatorChain; | |||
public BindingImpl(BindingBuilderImpl<BEAN, FIELDVALUE, TARGET> builder, | |||
SerializableFunction<BEAN, TARGET> getter, | |||
SerializableBiConsumer<BEAN, TARGET> setter) { | |||
this.binder = builder.getBinder(); | |||
this.field = builder.field; | |||
this.statusHandler = builder.statusHandler; | |||
converterValidatorChain = builder.converterValidatorChain; | |||
onValueChange = getField() | |||
.addValueChangeListener(this::handleFieldValueChange); | |||
this.getter = getter; | |||
this.setter = setter; | |||
} | |||
@Override | |||
public HasValue<FIELDVALUE> getField() { | |||
return field; | |||
} | |||
/** | |||
* Finds an appropriate locale to be used in conversion and validation. | |||
@@ -783,6 +852,16 @@ public class Binder<BEAN> implements Serializable { | |||
return toValidationStatus(result); | |||
} | |||
/** | |||
* Returns the {@code Binder} connected to this {@code Binding} | |||
* instance. | |||
* | |||
* @return the binder | |||
*/ | |||
protected Binder<BEAN> getBinder() { | |||
return binder; | |||
} | |||
private void notifyStatusHandler(ValidationStatus<?> status) { | |||
statusHandler.accept(status); | |||
} | |||
@@ -895,18 +974,18 @@ public class Binder<BEAN> implements Serializable { | |||
} | |||
/** | |||
* Creates a new binding for the given field. The returned binding may be | |||
* Creates a new binding for the given field. The returned builder may be | |||
* further configured before invoking | |||
* {@link Binding#bind(SerializableFunction, SerializableBiConsumer)} which | |||
* completes the binding. Until {@code Binding.bind} is called, the binding | |||
* has no effect. | |||
* {@link BindingBuilder#bind(SerializableFunction, SerializableBiConsumer)} | |||
* which completes the binding. Until {@code Binding.bind} is called, the | |||
* binding has no effect. | |||
* <p> | |||
* <strong>Note:</strong> Not all {@link HasValue} implementations support | |||
* passing {@code null} as the value. For these the Binder will | |||
* 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 BindingBuilder#withNullRepresentation(Object)}. | |||
* | |||
* @param <FIELDVALUE> | |||
* the value type of the field | |||
@@ -916,7 +995,7 @@ public class Binder<BEAN> implements Serializable { | |||
* | |||
* @see #bind(HasValue, SerializableFunction, SerializableBiConsumer) | |||
*/ | |||
public <FIELDVALUE> Binding<BEAN, FIELDVALUE> forField( | |||
public <FIELDVALUE> BindingBuilder<BEAN, FIELDVALUE> forField( | |||
HasValue<FIELDVALUE> field) { | |||
Objects.requireNonNull(field, "field cannot be null"); | |||
// clear previous errors for this field and any bean level validation | |||
@@ -977,11 +1056,13 @@ public class Binder<BEAN> implements Serializable { | |||
* @param setter | |||
* the function to write the field value to the property or null | |||
* if read-only | |||
* @return the newly created binding | |||
*/ | |||
public <FIELDVALUE> void bind(HasValue<FIELDVALUE> field, | |||
public <FIELDVALUE> Binding<BEAN, FIELDVALUE> bind( | |||
HasValue<FIELDVALUE> field, | |||
SerializableFunction<BEAN, FIELDVALUE> getter, | |||
SerializableBiConsumer<BEAN, FIELDVALUE> setter) { | |||
forField(field).bind(getter, setter); | |||
return forField(field).bind(getter, setter); | |||
} | |||
/** | |||
@@ -1311,7 +1392,7 @@ public class Binder<BEAN> implements Serializable { | |||
* @param statusLabel | |||
* the status label to set | |||
* @see #setValidationStatusHandler(BinderStatusHandler) | |||
* @see Binding#withStatusLabel(Label) | |||
* @see BindingBuilder#withStatusLabel(Label) | |||
*/ | |||
public void setStatusLabel(Label statusLabel) { | |||
if (statusHandler != null) { | |||
@@ -1349,7 +1430,7 @@ public class Binder<BEAN> implements Serializable { | |||
* @throws NullPointerException | |||
* for <code>null</code> status handler | |||
* @see #setStatusLabel(Label) | |||
* @see Binding#withValidationStatusHandler(ValidationStatusHandler) | |||
* @see BindingBuilder#withValidationStatusHandler(ValidationStatusHandler) | |||
*/ | |||
public void setValidationStatusHandler( | |||
BinderValidationStatusHandler<BEAN> statusHandler) { | |||
@@ -1390,8 +1471,8 @@ public class Binder<BEAN> implements Serializable { | |||
* <li>{@link #readBean(Object)} is called | |||
* <li>{@link #setBean(Object)} is called | |||
* <li>{@link #removeBean()} is called | |||
* <li>{@link Binding#bind(SerializableFunction, SerializableBiConsumer)} is | |||
* called | |||
* <li>{@link BindingBuilder#bind(SerializableFunction, SerializableBiConsumer)} | |||
* is called | |||
* <li>{@link Binder#validate()} or {@link Binding#validate()} is called | |||
* </ul> | |||
* | |||
@@ -1401,10 +1482,8 @@ public class Binder<BEAN> implements Serializable { | |||
* @see #setBean(Object) | |||
* @see #removeBean() | |||
* @see #forField(HasValue) | |||
* @see #forSelect(AbstractMultiSelect) | |||
* @see #validate() | |||
* @see Binding#validate() | |||
* @see Binding#bind(Object) | |||
* | |||
* @param listener | |||
* status change listener to add, not null | |||
@@ -1431,10 +1510,10 @@ public class Binder<BEAN> implements Serializable { | |||
* the handler to notify of status changes, not null | |||
* @return the new incomplete binding | |||
*/ | |||
protected <FIELDVALUE, TARGET> Binding<BEAN, TARGET> createBinding( | |||
protected <FIELDVALUE, TARGET> BindingBuilder<BEAN, TARGET> createBinding( | |||
HasValue<FIELDVALUE> field, Converter<FIELDVALUE, TARGET> converter, | |||
ValidationStatusHandler handler) { | |||
return new BindingImpl<>(this, field, converter, handler); | |||
return new BindingBuilderImpl<>(this, field, converter, handler); | |||
} | |||
/** |
@@ -22,13 +22,13 @@ import java.util.List; | |||
import java.util.Objects; | |||
import java.util.stream.Collectors; | |||
import com.vaadin.data.Binder.Binding; | |||
import com.vaadin.data.Binder.BindingBuilder; | |||
import com.vaadin.data.validator.BeanValidator; | |||
/** | |||
* Binder validation status change. Represents the outcome of binder level | |||
* validation. Has information about the validation results for the | |||
* {@link Binding#withValidator(Validator) field level} and | |||
* {@link BindingBuilder#withValidator(Validator) field level} and | |||
* {@link Binder#withValidator(Validator)binder level} validation. | |||
* <p> | |||
* Note: if there are any field level validation errors, the bean level | |||
@@ -149,7 +149,7 @@ public class BinderValidationStatus<BEAN> implements Serializable { | |||
* Gets the field level validation statuses. | |||
* <p> | |||
* The field level validtors have been added with | |||
* {@link Binding#withValidator(Validator)}. | |||
* {@link BindingBuilder#withValidator(Validator)}. | |||
* | |||
* @return the field validation statuses | |||
*/ | |||
@@ -175,7 +175,7 @@ public class BinderValidationStatus<BEAN> implements Serializable { | |||
* Gets the failed field level validation statuses. | |||
* <p> | |||
* The field level validtors have been added with | |||
* {@link Binding#withValidator(Validator)}. | |||
* {@link BindingBuilder#withValidator(Validator)}. | |||
* | |||
* @return a list of failed field level validation statuses | |||
*/ |
@@ -18,6 +18,7 @@ package com.vaadin.data; | |||
import java.util.EventObject; | |||
import com.vaadin.data.Binder.Binding; | |||
import com.vaadin.data.Binder.BindingBuilder; | |||
import com.vaadin.server.SerializableBiConsumer; | |||
import com.vaadin.server.SerializableFunction; | |||
@@ -32,8 +33,8 @@ import com.vaadin.server.SerializableFunction; | |||
* <li>{@link Binder#readBean(Object)} is called | |||
* <li>{@link Binder#setBean(Object)} is called | |||
* <li>{@link Binder#removeBean()} is called | |||
* <li>{@link Binding#bind(SerializableFunction, SerializableBiConsumer)} is | |||
* called | |||
* <li>{@link BindingBuilder#bind(SerializableFunction, SerializableBiConsumer)} | |||
* is called | |||
* <li>{@link Binder#validate()} or {@link Binding#validate()} is called | |||
* </ul> | |||
* |
@@ -20,14 +20,16 @@ import java.util.Objects; | |||
import java.util.Optional; | |||
import com.vaadin.data.Binder.Binding; | |||
import com.vaadin.data.Binder.BindingBuilder; | |||
/** | |||
* Represents the status of field validation. Status can be {@code Status.OK}, | |||
* {@code Status.ERROR} or {@code Status.RESET}. Status OK and ERROR are always | |||
* associated with a ValidationResult {@link #getResult}. | |||
* <p> | |||
* Use {@link Binding#withValidationStatusHandler(ValidationStatusHandler)} to | |||
* register a handler for field level validation status changes. | |||
* Use | |||
* {@link BindingBuilder#withValidationStatusHandler(ValidationStatusHandler)} | |||
* to register a handler for field level validation status changes. | |||
* | |||
* @author Vaadin Ltd | |||
* | |||
@@ -36,7 +38,7 @@ import com.vaadin.data.Binder.Binding; | |||
* status changed, matches the field type unless a converter has been | |||
* set | |||
* | |||
* @see Binding#withValidationStatusHandler(ValidationStatusHandler) | |||
* @see BindingBuilder#withValidationStatusHandler(ValidationStatusHandler) | |||
* @see Binding#validate() | |||
* @see ValidationStatusHandler | |||
* @see BinderValidationStatus |
@@ -18,13 +18,13 @@ package com.vaadin.data; | |||
import java.io.Serializable; | |||
import java.util.function.Consumer; | |||
import com.vaadin.data.Binder.Binding; | |||
import com.vaadin.data.Binder.BindingBuilder; | |||
import com.vaadin.ui.AbstractComponent; | |||
/** | |||
* Handler for {@link ValidationStatus} changes. | |||
* <p> | |||
* {@link Binding#withValidationStatusHandler(withValidationStatusHandler) | |||
* {@link BindingBuilder#withValidationStatusHandler(withValidationStatusHandler) | |||
* Register} an instance of this class to be able to override the default | |||
* handling, which is to show | |||
* {@link AbstractComponent#setComponentError(com.vaadin.server.ErrorMessage) an | |||
@@ -32,7 +32,7 @@ import com.vaadin.ui.AbstractComponent; | |||
* | |||
* @author Vaadin Ltd | |||
* | |||
* @see Binding#withValidationStatusHandler(withValidationStatusHandler) | |||
* @see BindingBuilder#withValidationStatusHandler(withValidationStatusHandler) | |||
* @see ValidationStatus | |||
* | |||
* @since 8.0 |
@@ -19,7 +19,7 @@ package com.vaadin.data.util.converter; | |||
import java.io.Serializable; | |||
import java.util.function.Function; | |||
import com.vaadin.data.Binder.Binding; | |||
import com.vaadin.data.Binder.BindingBuilder; | |||
import com.vaadin.data.Result; | |||
import com.vaadin.server.SerializableFunction; | |||
@@ -149,7 +149,7 @@ public interface Converter<PRESENTATION, MODEL> extends Serializable { | |||
* <p> | |||
* In most typical cases you should not need this method but instead only | |||
* need to define one converter for a binding using | |||
* {@link Binding#withConverter(Converter)}. | |||
* {@link BindingBuilder#withConverter(Converter)}. | |||
* | |||
* @param <T> | |||
* the model type of the resulting converter |
@@ -10,8 +10,8 @@ import org.junit.Assert; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import com.vaadin.data.BeanBinder.BeanBinding; | |||
import com.vaadin.data.Binder.Binding; | |||
import com.vaadin.data.BeanBinder.BeanBindingBuilder; | |||
import com.vaadin.data.Binder.BindingBuilder; | |||
import com.vaadin.tests.data.bean.BeanToValidate; | |||
public class BeanBinderTest | |||
@@ -178,18 +178,18 @@ public class BeanBinderTest | |||
@Test | |||
public void beanBindingChainingMethods() { | |||
Method[] methods = BeanBinding.class.getMethods(); | |||
Method[] methods = BeanBindingBuilder.class.getMethods(); | |||
for (int i = 0; i < methods.length; i++) { | |||
Method method = methods[i]; | |||
try { | |||
Method actualMethod = BeanBinding.class.getMethod( | |||
Method actualMethod = BeanBindingBuilder.class.getMethod( | |||
method.getName(), method.getParameterTypes()); | |||
Assert.assertNotSame( | |||
actualMethod + " should be overridden in " | |||
+ BeanBinding.class | |||
+ BeanBindingBuilder.class | |||
+ " with more specific return type ", | |||
Binding.class, actualMethod.getReturnType()); | |||
BindingBuilder.class, actualMethod.getReturnType()); | |||
} catch (NoSuchMethodException | SecurityException e) { | |||
throw new RuntimeException(e); | |||
} |
@@ -26,6 +26,7 @@ import org.junit.Before; | |||
import org.junit.Test; | |||
import com.vaadin.data.Binder.Binding; | |||
import com.vaadin.data.Binder.BindingBuilder; | |||
import com.vaadin.data.ValidationStatus.Status; | |||
import com.vaadin.data.util.converter.Converter; | |||
import com.vaadin.data.util.converter.StringToIntegerConverter; | |||
@@ -249,14 +250,15 @@ public class BinderBookOfVaadinTest { | |||
// Slider for integers between 1 and 10 | |||
Slider salaryLevelField = new Slider("Salary level", 1, 10); | |||
Binding<BookPerson, String> b1 = binder.forField(yearOfBirthField); | |||
Binding<BookPerson, Integer> b2 = b1.withConverter( | |||
BindingBuilder<BookPerson, String> b1 = binder | |||
.forField(yearOfBirthField); | |||
BindingBuilder<BookPerson, Integer> b2 = b1.withConverter( | |||
new StringToIntegerConverter("Must enter a number")); | |||
b2.bind(BookPerson::getYearOfBirth, BookPerson::setYearOfBirth); | |||
Binding<BookPerson, Double> salaryBinding1 = binder | |||
BindingBuilder<BookPerson, Double> salaryBinding1 = binder | |||
.forField(salaryLevelField); | |||
Binding<BookPerson, Integer> salaryBinding2 = salaryBinding1 | |||
BindingBuilder<BookPerson, Integer> salaryBinding2 = salaryBinding1 | |||
.withConverter(Double::intValue, Integer::doubleValue); | |||
salaryBinding2.bind(BookPerson::getSalaryLevel, | |||
BookPerson::setSalaryLevel); | |||
@@ -308,9 +310,9 @@ public class BinderBookOfVaadinTest { | |||
.withValidator( | |||
returnDate -> !returnDate | |||
.isBefore(departing.getValue()), | |||
"Cannot return before departing"); | |||
"Cannot return before departing") | |||
.bind(Trip::getReturnDate, Trip::setReturnDate); | |||
returnBinding.bind(Trip::getReturnDate, Trip::setReturnDate); | |||
departing.addValueChangeListener(event -> returnBinding.validate()); | |||
LocalDate past = LocalDate.now(); | |||
@@ -361,9 +363,9 @@ public class BinderBookOfVaadinTest { | |||
.withValidator( | |||
returnDate -> !returnDate | |||
.isBefore(departing.getValue()), | |||
"Cannot return before departing"); | |||
"Cannot return before departing") | |||
.bind(Trip::getReturnDate, Trip::setReturnDate); | |||
returnBinding.bind(Trip::getReturnDate, Trip::setReturnDate); | |||
departing.addValueChangeListener(event -> returnBinding.validate()); | |||
LocalDate past = LocalDate.now(); |
@@ -29,6 +29,7 @@ import org.junit.Before; | |||
import org.junit.Test; | |||
import com.vaadin.data.Binder.Binding; | |||
import com.vaadin.data.Binder.BindingBuilder; | |||
import com.vaadin.data.util.converter.StringToIntegerConverter; | |||
import com.vaadin.data.util.converter.ValueContext; | |||
import com.vaadin.data.validator.NotEmptyValidator; | |||
@@ -73,7 +74,7 @@ public class BinderConverterValidatorTest | |||
@Test | |||
public void bound_validatorsAreOK_noErrors() { | |||
Binding<Person, String> binding = binder.forField(nameField); | |||
BindingBuilder<Person, String> binding = binder.forField(nameField); | |||
binding.withValidator(Validator.alwaysPass()).bind(Person::getFirstName, | |||
Person::setFirstName); | |||
@@ -87,7 +88,7 @@ public class BinderConverterValidatorTest | |||
@SuppressWarnings("serial") | |||
@Test | |||
public void bound_validatorsFail_errors() { | |||
Binding<Person, String> binding = binder.forField(nameField); | |||
BindingBuilder<Person, String> binding = binder.forField(nameField); | |||
binding.withValidator(Validator.alwaysPass()); | |||
String msg1 = "foo"; | |||
String msg2 = "bar"; | |||
@@ -221,7 +222,7 @@ public class BinderConverterValidatorTest | |||
bean.setStatus("1"); | |||
Binder<StatusBean> binder = new Binder<>(); | |||
Binding<StatusBean, String> binding = binder.forField(field) | |||
BindingBuilder<StatusBean, String> binding = binder.forField(field) | |||
.withConverter(presentation -> { | |||
if (presentation.equals("OK")) { | |||
return "1"; | |||
@@ -266,7 +267,7 @@ public class BinderConverterValidatorTest | |||
public void validate_failedBeanValidatorWithFieldValidator() { | |||
String msg = "foo"; | |||
Binding<Person, String> binding = binder.forField(nameField) | |||
BindingBuilder<Person, String> binding = binder.forField(nameField) | |||
.withValidator(new NotEmptyValidator<>(msg)); | |||
binding.bind(Person::getFirstName, Person::setFirstName); | |||
@@ -286,7 +287,7 @@ public class BinderConverterValidatorTest | |||
public void validate_failedBothBeanValidatorAndFieldValidator() { | |||
String msg1 = "foo"; | |||
Binding<Person, String> binding = binder.forField(nameField) | |||
BindingBuilder<Person, String> binding = binder.forField(nameField) | |||
.withValidator(new NotEmptyValidator<>(msg1)); | |||
binding.bind(Person::getFirstName, Person::setFirstName); | |||
@@ -322,7 +323,7 @@ public class BinderConverterValidatorTest | |||
@Test | |||
public void binder_saveIfValid() { | |||
String msg1 = "foo"; | |||
Binding<Person, String> binding = binder.forField(nameField) | |||
BindingBuilder<Person, String> binding = binder.forField(nameField) | |||
.withValidator(new NotEmptyValidator<>(msg1)); | |||
binding.bind(Person::getFirstName, Person::setFirstName); | |||
@@ -554,11 +555,11 @@ public class BinderConverterValidatorTest | |||
public void save_validationErrors_exceptionContainsErrors() | |||
throws ValidationException { | |||
String msg = "foo"; | |||
Binding<Person, String> nameBinding = binder.forField(nameField) | |||
BindingBuilder<Person, String> nameBinding = binder.forField(nameField) | |||
.withValidator(new NotEmptyValidator<>(msg)); | |||
nameBinding.bind(Person::getFirstName, Person::setFirstName); | |||
Binding<Person, Integer> ageBinding = binder.forField(ageField) | |||
BindingBuilder<Person, Integer> ageBinding = binder.forField(ageField) | |||
.withConverter(stringToInteger).withValidator(notNegative); | |||
ageBinding.bind(Person::getAge, Person::setAge); | |||
@@ -585,7 +586,7 @@ public class BinderConverterValidatorTest | |||
@Test | |||
public void binderBindAndLoad_clearsErrors() { | |||
Binding<Person, String> binding = binder.forField(nameField) | |||
BindingBuilder<Person, String> binding = binder.forField(nameField) | |||
.withValidator(notEmpty); | |||
binding.bind(Person::getFirstName, Person::setFirstName); | |||
binder.withValidator(bean -> !bean.getFirstName().contains("error"), | |||
@@ -621,7 +622,7 @@ public class BinderConverterValidatorTest | |||
// bind a new field that has invalid value in bean | |||
TextField lastNameField = new TextField(); | |||
person.setLastName(""); | |||
Binding<Person, String> binding2 = binder.forField(lastNameField) | |||
BindingBuilder<Person, String> binding2 = binder.forField(lastNameField) | |||
.withValidator(notEmpty); | |||
binding2.bind(Person::getLastName, Person::setLastName); | |||
@@ -663,15 +664,15 @@ public class BinderConverterValidatorTest | |||
final SerializablePredicate<String> lengthPredicate = v -> v | |||
.length() > 2; | |||
Binding<Person, String> firstNameBinding = binder.forField(nameField) | |||
.withValidator(lengthPredicate, "length"); | |||
BindingBuilder<Person, String> firstNameBinding = binder | |||
.forField(nameField).withValidator(lengthPredicate, "length"); | |||
firstNameBinding.bind(Person::getFirstName, Person::setFirstName); | |||
Binding<Person, String> lastNameBinding = binder.forField(lastNameField) | |||
.withValidator(v -> !nameField.getValue().isEmpty() | |||
|| lengthPredicate.test(v), "err") | |||
.withValidator(lengthPredicate, "length"); | |||
lastNameBinding.bind(Person::getLastName, Person::setLastName); | |||
.withValidator(lengthPredicate, "length") | |||
.bind(Person::getLastName, Person::setLastName); | |||
// this will be triggered as a new bean is bound with binder.bind(), | |||
// causing a validation error to be visible until reset is done |
@@ -22,6 +22,7 @@ import org.junit.Before; | |||
import org.junit.Test; | |||
import com.vaadin.data.Binder.Binding; | |||
import com.vaadin.data.Binder.BindingBuilder; | |||
import com.vaadin.data.util.converter.StringToIntegerConverter; | |||
import com.vaadin.tests.data.bean.Person; | |||
@@ -45,7 +46,7 @@ public class BinderStatusChangeTest | |||
public void bindBinding_unbound_eventWhenBoundEndnoEventsBeforeBound() { | |||
binder.addStatusChangeListener(this::statusChanged); | |||
Binding<Person, String> binding = binder.forField(nameField); | |||
BindingBuilder<Person, String> binding = binder.forField(nameField); | |||
nameField.setValue(""); | |||
Assert.assertNull(event.get()); | |||
@@ -377,8 +378,8 @@ public class BinderStatusChangeTest | |||
@Test | |||
public void validateBinding_noValidationErrors_statusEventWithoutErrors() { | |||
Binding<Person, String> binding = binder.forField(nameField); | |||
binding.bind(Person::getFirstName, Person::setFirstName); | |||
Binding<Person, String> binding = binder.forField(nameField) | |||
.bind(Person::getFirstName, Person::setFirstName); | |||
binder.forField(ageField) | |||
.withConverter(new StringToIntegerConverter("")) | |||
.bind(Person::getAge, Person::setAge); | |||
@@ -394,8 +395,8 @@ public class BinderStatusChangeTest | |||
@Test | |||
public void validateBinding_validationErrors_statusEventWithError() { | |||
Binding<Person, String> binding = binder.forField(nameField) | |||
.withValidator(name -> false, ""); | |||
binding.bind(Person::getFirstName, Person::setFirstName); | |||
.withValidator(name -> false, "") | |||
.bind(Person::getFirstName, Person::setFirstName); | |||
binder.forField(ageField) | |||
.withConverter(new StringToIntegerConverter("")) | |||
.bind(Person::getAge, Person::setAge); |
@@ -13,7 +13,7 @@ import org.junit.Assert; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import com.vaadin.data.Binder.Binding; | |||
import com.vaadin.data.Binder.BindingBuilder; | |||
import com.vaadin.data.util.converter.StringToIntegerConverter; | |||
import com.vaadin.data.validator.NotEmptyValidator; | |||
import com.vaadin.server.ErrorMessage; | |||
@@ -331,7 +331,7 @@ public class BinderTest extends BinderTestBase<Binder<Person>, Person> { | |||
TextField textField = new TextField(); | |||
Assert.assertFalse(textField.isRequiredIndicatorVisible()); | |||
Binding<Person, String> binding = binder.forField(textField); | |||
BindingBuilder<Person, String> binding = binder.forField(textField); | |||
Assert.assertFalse(textField.isRequiredIndicatorVisible()); | |||
binding.setRequired("foobar"); | |||
@@ -357,7 +357,7 @@ public class BinderTest extends BinderTestBase<Binder<Person>, Person> { | |||
textField.setLocale(Locale.CANADA); | |||
Assert.assertFalse(textField.isRequiredIndicatorVisible()); | |||
Binding<Person, String> binding = binder.forField(textField); | |||
BindingBuilder<Person, String> binding = binder.forField(textField); | |||
Assert.assertFalse(textField.isRequiredIndicatorVisible()); | |||
AtomicInteger invokes = new AtomicInteger(); | |||
@@ -23,6 +23,7 @@ import org.junit.Before; | |||
import org.junit.Test; | |||
import com.vaadin.data.Binder.Binding; | |||
import com.vaadin.data.Binder.BindingBuilder; | |||
import com.vaadin.data.ValidationStatus.Status; | |||
import com.vaadin.tests.data.bean.Person; | |||
import com.vaadin.ui.Label; | |||
@@ -48,7 +49,7 @@ public class BinderValidationStatusTest | |||
@Test | |||
public void bindingWithStatusHandler_handlerGetsEvents() { | |||
AtomicReference<ValidationStatus<?>> statusCapture = new AtomicReference<>(); | |||
Binding<Person, String> binding = binder.forField(nameField) | |||
BindingBuilder<Person, String> binding = binder.forField(nameField) | |||
.withValidator(notEmpty).withValidationStatusHandler(evt -> { | |||
Assert.assertNull(statusCapture.get()); | |||
statusCapture.set(evt); | |||
@@ -86,8 +87,7 @@ public class BinderValidationStatusTest | |||
public void bindingWithStatusHandler_defaultStatusHandlerIsReplaced() { | |||
Binding<Person, String> binding = binder.forField(nameField) | |||
.withValidator(notEmpty).withValidationStatusHandler(evt -> { | |||
}); | |||
binding.bind(Person::getFirstName, Person::setFirstName); | |||
}).bind(Person::getFirstName, Person::setFirstName); | |||
Assert.assertNull(nameField.getComponentError()); | |||
@@ -106,8 +106,8 @@ public class BinderValidationStatusTest | |||
Label label = new Label(); | |||
Binding<Person, String> binding = binder.forField(nameField) | |||
.withValidator(notEmpty).withStatusLabel(label); | |||
binding.bind(Person::getFirstName, Person::setFirstName); | |||
.withValidator(notEmpty).withStatusLabel(label) | |||
.bind(Person::getFirstName, Person::setFirstName); | |||
nameField.setValue(""); | |||
@@ -133,8 +133,8 @@ public class BinderValidationStatusTest | |||
Label label = new Label(); | |||
Binding<Person, String> binding = binder.forField(nameField) | |||
.withValidator(notEmpty).withStatusLabel(label); | |||
binding.bind(Person::getFirstName, Person::setFirstName); | |||
.withValidator(notEmpty).withStatusLabel(label) | |||
.bind(Person::getFirstName, Person::setFirstName); | |||
Assert.assertNull(nameField.getComponentError()); | |||
@@ -150,7 +150,7 @@ public class BinderValidationStatusTest | |||
@Test(expected = IllegalStateException.class) | |||
public void bindingWithStatusHandler_addAfterBound() { | |||
Binding<Person, String> binding = binder.forField(nameField) | |||
BindingBuilder<Person, String> binding = binder.forField(nameField) | |||
.withValidator(notEmpty); | |||
binding.bind(Person::getFirstName, Person::setFirstName); | |||
@@ -161,7 +161,7 @@ public class BinderValidationStatusTest | |||
public void bindingWithStatusLabel_addAfterBound() { | |||
Label label = new Label(); | |||
Binding<Person, String> binding = binder.forField(nameField) | |||
BindingBuilder<Person, String> binding = binder.forField(nameField) | |||
.withValidator(notEmpty); | |||
binding.bind(Person::getFirstName, Person::setFirstName); | |||
@@ -172,7 +172,7 @@ public class BinderValidationStatusTest | |||
public void bindingWithStatusLabel_setAfterHandler() { | |||
Label label = new Label(); | |||
Binding<Person, String> binding = binder.forField(nameField); | |||
BindingBuilder<Person, String> binding = binder.forField(nameField); | |||
binding.withValidationStatusHandler(NOOP); | |||
@@ -183,7 +183,7 @@ public class BinderValidationStatusTest | |||
public void bindingWithStatusHandler_setAfterLabel() { | |||
Label label = new Label(); | |||
Binding<Person, String> binding = binder.forField(nameField); | |||
BindingBuilder<Person, String> binding = binder.forField(nameField); | |||
binding.withStatusLabel(label); | |||
@@ -193,7 +193,7 @@ public class BinderValidationStatusTest | |||
@Test(expected = IllegalStateException.class) | |||
public void bindingWithStatusHandler_setAfterOtherHandler() { | |||
Binding<Person, String> binding = binder.forField(nameField); | |||
BindingBuilder<Person, String> binding = binder.forField(nameField); | |||
binding.withValidationStatusHandler(NOOP); | |||
@@ -394,8 +394,7 @@ public class BinderValidationStatusTest | |||
public void binderWithStatusHandler_defaultStatusHandlerIsReplaced() { | |||
Binding<Person, String> binding = binder.forField(nameField) | |||
.withValidator(notEmpty).withValidationStatusHandler(evt -> { | |||
}); | |||
binding.bind(Person::getFirstName, Person::setFirstName); | |||
}).bind(Person::getFirstName, Person::setFirstName); | |||
Assert.assertNull(nameField.getComponentError()); | |||
@@ -414,8 +413,8 @@ public class BinderValidationStatusTest | |||
Label label = new Label(); | |||
Binding<Person, String> binding = binder.forField(nameField) | |||
.withValidator(notEmpty).withStatusLabel(label); | |||
binding.bind(Person::getFirstName, Person::setFirstName); | |||
.withValidator(notEmpty).withStatusLabel(label) | |||
.bind(Person::getFirstName, Person::setFirstName); | |||
Assert.assertNull(nameField.getComponentError()); | |||
@@ -431,7 +430,7 @@ public class BinderValidationStatusTest | |||
@Test(expected = IllegalStateException.class) | |||
public void binderWithStatusHandler_addAfterBound() { | |||
Binding<Person, String> binding = binder.forField(nameField) | |||
BindingBuilder<Person, String> binding = binder.forField(nameField) | |||
.withValidator(notEmpty); | |||
binding.bind(Person::getFirstName, Person::setFirstName); | |||
@@ -442,7 +441,7 @@ public class BinderValidationStatusTest | |||
public void binderWithStatusLabel_addAfterBound() { | |||
Label label = new Label(); | |||
Binding<Person, String> binding = binder.forField(nameField) | |||
BindingBuilder<Person, String> binding = binder.forField(nameField) | |||
.withValidator(notEmpty); | |||
binding.bind(Person::getFirstName, Person::setFirstName); | |||
@@ -453,7 +452,7 @@ public class BinderValidationStatusTest | |||
public void binderWithStatusLabel_setAfterHandler() { | |||
Label label = new Label(); | |||
Binding<Person, String> binding = binder.forField(nameField); | |||
BindingBuilder<Person, String> binding = binder.forField(nameField); | |||
binding.bind(Person::getFirstName, Person::setFirstName); | |||
binder.setValidationStatusHandler(event -> { | |||
@@ -466,7 +465,7 @@ public class BinderValidationStatusTest | |||
public void binderWithStatusHandler_setAfterLabel() { | |||
Label label = new Label(); | |||
Binding<Person, String> binding = binder.forField(nameField); | |||
BindingBuilder<Person, String> binding = binder.forField(nameField); | |||
binding.bind(Person::getFirstName, Person::setFirstName); | |||
binder.setStatusLabel(label); | |||
@@ -484,7 +483,7 @@ public class BinderValidationStatusTest | |||
public void binderWithStatusHandler_replaceHandler() { | |||
AtomicReference<BinderValidationStatus<?>> capture = new AtomicReference<>(); | |||
Binding<Person, String> binding = binder.forField(nameField); | |||
BindingBuilder<Person, String> binding = binder.forField(nameField); | |||
binding.bind(Person::getFirstName, Person::setFirstName); | |||
binder.setValidationStatusHandler(results -> { |
@@ -17,7 +17,7 @@ package com.vaadin.data.validator; | |||
import java.util.Objects; | |||
import com.vaadin.data.Binder.Binding; | |||
import com.vaadin.data.Binder.BindingBuilder; | |||
import com.vaadin.data.HasValue; | |||
import com.vaadin.data.ValidationResult; | |||
import com.vaadin.data.Validator; | |||
@@ -33,13 +33,13 @@ import com.vaadin.data.util.converter.ValueContext; | |||
* This validator can be suitable for fields that have been marked as required | |||
* with {@link HasValue#setRequiredIndicatorVisible(boolean)}. | |||
* <p> | |||
* Note that {@link Binding#setRequired(com.vaadin.data.ErrorMessageProvider)} | |||
* Note that {@link BindingBuilder#setRequired(com.vaadin.data.ErrorMessageProvider)} | |||
* does almost the same thing, but verifies against the value NOT being equal to | |||
* what {@link HasValue#getEmptyValue()} returns and sets the required indicator | |||
* visible with {@link HasValue#setRequiredIndicatorVisible(boolean)}. | |||
* | |||
* @see HasValue#setRequiredIndicatorVisible(boolean) | |||
* @see Binding#setRequired(com.vaadin.data.ErrorMessageProvider) | |||
* @see BindingBuilder#setRequired(com.vaadin.data.ErrorMessageProvider) | |||
* @author Vaadin Ltd | |||
* @since 8.0 | |||
* |