Browse Source

Add methods to control validation (#11945)

- Enable / disable all validators on Binder level
- Enable / disable validators on Binding level
- add writeBeanAsDraft(bean,boolean) for writing draft bean with validators disabled

Fixes https://github.com/vaadin/framework/issues/10709

Co-authored-by: Zhe Sun <31067185+ZheSun88@users.noreply.github.com>
tags/8.11.0.alpha1
Tatu Lund 4 years ago
parent
commit
d35bd4cde4
No account linked to committer's email address

+ 14
- 0
pom.xml View File

@@ -61,6 +61,13 @@
</properties>

<pluginRepositories>
<pluginRepository>
<id>central</id>
<url>https://repo.maven.apache.org/maven2/</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>vaadin-snapshots</id>
<url>https://oss.sonatype.org/content/repositories/vaadin-snapshots/</url>
@@ -74,6 +81,13 @@
</pluginRepositories>

<repositories>
<repository>
<id>central</id>
<url>https://repo.maven.apache.org/maven2/</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>vaadin-snapshots</id>
<url>https://oss.sonatype.org/content/repositories/vaadin-snapshots/</url>

+ 114
- 8
server/src/main/java/com/vaadin/data/Binder.java View File

@@ -254,6 +254,25 @@ public class Binder<BEAN> implements Serializable {
* @since 8.10
*/
public boolean isAsRequiredEnabled();

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

/**
* Returns if validators are currently disabled or not
*
* @return A boolean value
*
* @since
*/
public boolean isValidatorsDisabled();
}

/**
@@ -800,6 +819,7 @@ public class Binder<BEAN> implements Serializable {
private final HasValue<FIELDVALUE> field;
private BindingValidationStatusHandler statusHandler;
private boolean isStatusHandlerChanged;
private Binding<BEAN, TARGET> binding;

private boolean bound;

@@ -855,6 +875,7 @@ public class Binder<BEAN> implements Serializable {

bound = true;
getBinder().incompleteBindings.remove(getField());
this.binding = binding;

return binding;
}
@@ -889,6 +910,7 @@ public class Binder<BEAN> implements Serializable {
Binding binding = ((BindingBuilder) finalBinding).bind(getter,
setter);
getBinder().boundProperties.put(propertyName, binding);
this.binding = binding;
return binding;
} finally {
getBinder().incompleteMemberFieldBindings.remove(getField());
@@ -909,8 +931,17 @@ public class Binder<BEAN> implements Serializable {
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;
}

@@ -1059,6 +1090,8 @@ public class Binder<BEAN> implements Serializable {

private boolean asRequiredSet;

private boolean validatorsDisabled = false;

public BindingImpl(BindingBuilderImpl<BEAN, FIELDVALUE, TARGET> builder,
ValueProvider<BEAN, TARGET> getter,
Setter<BEAN, TARGET> setter) {
@@ -1341,6 +1374,16 @@ public class Binder<BEAN> implements Serializable {
public boolean isAsRequiredEnabled() {
return field.isRequiredIndicatorVisible();
}

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

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

/**
@@ -1446,6 +1489,8 @@ public class Binder<BEAN> implements Serializable {

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
@@ -1862,7 +1907,28 @@ public class Binder<BEAN> implements Serializable {
* @since 8.10
*/
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
* @since
*/
public void writeBeanAsDraft(BEAN bean, boolean forced) {
doWriteDraft(bean, new ArrayList<>(bindings),forced);
}

/**
@@ -1960,14 +2026,23 @@ public class Binder<BEAN> implements Serializable {
* 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);
}
}

/**
@@ -2037,7 +2112,14 @@ public class Binder<BEAN> implements Serializable {
*/
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;
}

@@ -3035,6 +3117,30 @@ public class Binder<BEAN> implements Serializable {
.ifPresent(Binding::unbind);
}

/**
* Control whether validators including bean level validators are
* disabled or enabled globally for this Binder.
*
* @param validatorsDisabled Boolean value
*
* @since
*/
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
*
* @since
*/
public boolean isValidatorsDisabled() {
return validatorsDisabled;
}

private static final Logger getLogger() {
return Logger.getLogger(Binder.class.getName());
}

+ 77
- 2
server/src/test/java/com/vaadin/data/BinderTest.java View File

@@ -274,8 +274,11 @@ public class BinderTest extends BinderTestBase<Binder<Person>, Person> {
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");
if (value.equals("Mike")) {
return ValidationResult.ok();
} else {
return ValidationResult.error("value must be Mike");
}
})
.bind(Person::getFirstName, Person::setFirstName);
binder.forField(ageField)
@@ -300,6 +303,78 @@ public class BinderTest extends BinderTestBase<Binder<Person>, Person> {
// 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

Loading…
Cancel
Save