Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add methods to control validation #8094

Merged
merged 5 commits into from
May 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 105 additions & 7 deletions flow-data/src/main/java/com/vaadin/flow/data/binder/Binder.java
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,21 @@ default BindingValidationStatus<TARGET> validate() {
* {@code true} otherwise (default)
*/
public boolean isAsRequiredEnabled();

/**
* Define whether validators are disabled or enabled for this
* specific binding.
*
* @param validatorsDisabled A boolean value.
*/
public void setValidatorsDisabled(boolean validatorsDisabled);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MINOR "public" is redundant in this context. rule


/**
* Returns if validators are currently disabled or not.
*
* @return A boolean value.
*/
public boolean isValidatorsDisabled();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MINOR "public" is redundant in this context. rule

}

/**
Expand Down Expand Up @@ -754,6 +769,7 @@ protected static class BindingBuilderImpl<BEAN, FIELDVALUE, TARGET>
private final HasValue<?, FIELDVALUE> field;
private BindingValidationStatusHandler statusHandler;
private boolean isStatusHandlerChanged;
private Binding<BEAN, TARGET> binding;

private boolean bound;

Expand Down Expand Up @@ -815,6 +831,7 @@ public Binding<BEAN, TARGET> bind(ValueProvider<BEAN, TARGET> getter,
if (getBinder().incompleteBindings != null) {
getBinder().incompleteBindings.remove(getField());
}
this.binding = binding;

return binding;
}
Expand Down Expand Up @@ -849,6 +866,7 @@ public Binding<BEAN, TARGET> bind(String propertyName) {
Binding binding = ((BindingBuilder) finalBinding).bind(getter,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAJOR Rename "binding" which hides the field declared at line 772. rule

setter);
getBinder().boundProperties.put(propertyName, binding);
this.binding = binding;
return binding;
} finally {
if (getBinder().incompleteMemberFieldBindings != null) {
Expand All @@ -872,8 +890,17 @@ public BindingBuilder<BEAN, TARGET> withValidator(
checkUnbound();
Objects.requireNonNull(validator, "validator cannot be null");

Validator<? super TARGET> wrappedValidator = ((value, context) -> {
if (getBinder().isValidatorsDisabled() ||
(binding != null && binding.isValidatorsDisabled())) {
return ValidationResult.ok();
} else {
return validator.apply(value, context);
}
});

converterValidatorChain = ((Converter<FIELDVALUE, TARGET>) converterValidatorChain)
.chain(new ValidatorAsConverter<>(validator));
.chain(new ValidatorAsConverter<>(wrappedValidator));
return this;
}

Expand Down Expand Up @@ -1026,6 +1053,8 @@ protected static class BindingImpl<BEAN, FIELDVALUE, TARGET>

private final boolean asRequiredSet;

private boolean validatorsDisabled = false;

public BindingImpl(BindingBuilderImpl<BEAN, FIELDVALUE, TARGET> builder,
ValueProvider<BEAN, TARGET> getter,
Setter<BEAN, TARGET> setter) {
Expand Down Expand Up @@ -1306,6 +1335,16 @@ public void setAsRequiredEnabled(boolean asRequiredEnabled) {
public boolean isAsRequiredEnabled() {
return field.isRequiredIndicatorVisible();
}

@Override
public void setValidatorsDisabled(boolean validatorsDisabled) {
this.validatorsDisabled = validatorsDisabled;
}

@Override
public boolean isValidatorsDisabled() {
return validatorsDisabled;
}
}

/**
Expand Down Expand Up @@ -1412,6 +1451,8 @@ void setIdentity() {

private Set<Binding<BEAN, ?>> changedBindings = new LinkedHashSet<>();

private boolean validatorsDisabled = false;

/**
* Creates a binder using a custom {@link PropertySet} implementation for
* finding and resolving property names for
Expand Down Expand Up @@ -1831,7 +1872,27 @@ public void writeBean(BEAN bean) throws ValidationException {
* {@code null}
*/
public void writeBeanAsDraft(BEAN bean) {
doWriteDraft(bean, new ArrayList<>(bindings));
doWriteDraft(bean, new ArrayList<>(bindings),false);
}

/**
* Writes successfully converted changes from the bound fields bypassing
* all the Validation or all fields passing conversion if forced = true.
* If the conversion fails, the value written to the bean will be null.
*
* @see #writeBean(Object)
* @see #writeBeanIfValid(Object)
* @see #readBean(Object)
* @see #setBean(Object)
*
* @param bean
* the object to which to write the field values, not
* {@code null}
* @param forced
* disable all Validators during write
*/
public void writeBeanAsDraft(BEAN bean, boolean forced) {
doWriteDraft(bean, new ArrayList<>(bindings),forced);
}

/**
Expand Down Expand Up @@ -1929,14 +1990,24 @@ private BinderValidationStatus<BEAN> doWriteIfValid(BEAN bean,
* the bean to write field values into
* @param bindings
* the set of bindings to write to the bean
* @param forced
* disable validators during write if true
*/
@SuppressWarnings({ "unchecked" })
private void doWriteDraft(BEAN bean,
Collection<Binding<BEAN, ?>> bindings) {
private void doWriteDraft(BEAN bean,
Collection<Binding<BEAN, ?>> bindings, boolean forced) {
Objects.requireNonNull(bean, "bean cannot be null");

bindings.forEach(binding -> ((BindingImpl<BEAN, ?, ?>) binding)
.writeFieldValue(bean));
if (!forced) {
bindings.forEach(binding -> ((BindingImpl<BEAN, ?, ?>) binding)
.writeFieldValue(bean));
} else {
boolean isDisabled = isValidatorsDisabled();
setValidatorsDisabled(true);
bindings.forEach(binding -> ((BindingImpl<BEAN, ?, ?>) binding)
.writeFieldValue(bean));
setValidatorsDisabled(isDisabled);
}
}

/**
Expand Down Expand Up @@ -1998,7 +2069,14 @@ protected void restoreBeanState(BEAN bean,
*/
public Binder<BEAN> withValidator(Validator<? super BEAN> validator) {
Objects.requireNonNull(validator, "validator cannot be null");
validators.add(validator);
Validator<? super BEAN> wrappedValidator = ((value, context) -> {
if (isValidatorsDisabled()) {
return ValidationResult.ok();
} else {
return validator.apply(value, context);
}
});
validators.add(wrappedValidator);
return this;
}

Expand Down Expand Up @@ -2986,4 +3064,24 @@ public void removeBinding(String propertyName) {
Optional.ofNullable(boundProperties.get(propertyName))
.ifPresent(Binding::unbind);
}

/**
* Control whether validators including bean level validators are
* disabled or enabled globally for this Binder.
*
* @param validatorsDisabled Boolean value.
*/
public void setValidatorsDisabled(boolean validatorsDisabled) {
this.validatorsDisabled = validatorsDisabled;
}

/**
* Returns if the validators including bean level validators
* are disabled or enabled for this Binder.
*
* @return Boolean value
*/
public boolean isValidatorsDisabled() {
return validatorsDisabled;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,72 @@ private void do_test_save_bound_beanAsDraft(boolean setBean) {
// age is written to draft even if firstname validation
// fails
assertEquals(age, person.getAge());

binder.writeBeanAsDraft(person,true);
// name is now written despite validation as write was forced
assertEquals(fieldValue, person.getFirstName());
}

@Test
public void save_bound_bean_disable_validation_binding() throws ValidationException {
Binder<Person> binder = new Binder<>();
Binding<Person, String> nameBinding = binder.forField(nameField)
.withValidator((value,context) -> {
if (value.equals("Mike")) return ValidationResult.ok();
else return ValidationResult.error("value must be Mike");
})
.bind(Person::getFirstName, Person::setFirstName);
binder.forField(ageField)
.withConverter(new StringToIntegerConverter(""))
.bind(Person::getAge, Person::setAge);

Person person = new Person();

String fieldValue = "John";
nameField.setValue(fieldValue);

int age = 10;
ageField.setValue("10");

person.setFirstName("Mark");

nameBinding.setValidatorsDisabled(true);
binder.writeBean(person);

// name is now written as validation was disabled
assertEquals(fieldValue, person.getFirstName());
assertEquals(age, person.getAge());
}

@Test
public void save_bound_bean_disable_validation_binder() throws ValidationException {
Binder<Person> binder = new Binder<>();
binder.forField(nameField)
.withValidator((value,context) -> {
if (value.equals("Mike")) return ValidationResult.ok();
else return ValidationResult.error("value must be Mike");
})
.bind(Person::getFirstName, Person::setFirstName);
binder.forField(ageField)
.withConverter(new StringToIntegerConverter(""))
.bind(Person::getAge, Person::setAge);

Person person = new Person();

String fieldValue = "John";
nameField.setValue(fieldValue);

int age = 10;
ageField.setValue("10");

person.setFirstName("Mark");

binder.setValidatorsDisabled(true);
binder.writeBean(person);

// name is now written as validation was disabled
assertEquals(fieldValue, person.getFirstName());
assertEquals(age, person.getAge());
}

@Test
Expand Down