How to Validate Two or More Fields in Combination

How can I validate two or more fields in combination?

For multiple properties validation, you should use class-level constraints. From
Bean Validation Sneak Peek part II: custom constraints:

Class-level constraints

Some of you have expressed concerns
about the ability to apply a
constraint spanning multiple
properties, or to express constraint
which depend on several properties.
The classical example is address
validation. Addresses have intricate
rules:

  • a street name is somewhat standard and must certainly have a length limit
  • the zip code structure entirely depends on the country
  • the city can often be correlated to a zipcode and some error checking can
    be done (provided that a validation
    service is accessible)
  • because of these interdependencies a simple property level constraint does
    to fit the bill

The solution offered by the Bean
Validation specification is two-fold:

  • it offers the ability to force a set of constraints to be applied before an
    other set of constraints through the
    use of groups and group sequences.
    This subject will be covered in the
    next blog entry
  • it allows to define class level constraints

Class level constraints are regular
constraints (annotation /
implementation duo) which apply on a
class rather than a property. Said
differently, class-level constraints
receive the object instance (rather
than the property value) in isValid.

@AddressAnnotation 
public class Address {
@NotNull @Max(50) private String street1;
@Max(50) private String street2;
@Max(10) @NotNull private String zipCode;
@Max(20) @NotNull String city;
@NotNull private Country country;

...
}

@Constraint(validatedBy = MultiCountryAddressValidator.class)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface AddressAnnotation {
String message() default "{error.address}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}

public class MultiCountryAddressValidator implements ConstraintValidator<AddressAnnotation, Address> {
public void initialize(AddressAnnotation constraintAnnotation) {
// initialize the zipcode/city/country correlation service
}

/**
* Validate zipcode and city depending on the country
*/
public boolean isValid(Address object, ConstraintValidatorContext context) {
if (!(object instanceof Address)) {
throw new IllegalArgumentException("@AddressAnnotation only applies to Address objects");
}
Address address = (Address) object;
Country country = address.getCountry();
if (country.getISO2() == "FR") {
// check address.getZipCode() structure for France (5 numbers)
// check zipcode and city correlation (calling an external service?)
return isValid;
} else if (country.getISO2() == "GR") {
// check address.getZipCode() structure for Greece
// no zipcode / city correlation available at the moment
return isValid;
}
// ...
}
}

The advanced address validation rules
have been left out of the address
object and implemented by
MultiCountryAddressValidator. By
accessing the object instance, class
level constraints have a lot of
flexibility and can validate multiple
correlated properties. Note that
ordering is left out of the equation
here, we will come back to it in the
next post.

The expert group has discussed various
multiple properties support
approaches: we think the class level
constraint approach provides both
enough simplicity and flexibility
compared to other property level
approaches involving dependencies.
Your feedback is welcome.

How can I validate two or more fields in combination? in Methods

You can refer to https://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/?v=6.1#section-cross-parameter-constraints to get more details.

You can change your code as below:

@SupportedValidationTarget(ValidationTarget.PARAMETERS)
public class ValidarImpl implements
ConstraintValidator < Validar, Object[] > {

@Override
public boolean isValid(Object[] value, ConstraintValidatorContext context) {
if (value.length != 2) {
throw new IllegalArgumentException("Illegal method signature");
}

if (value[0] == null || value[1] == null) {
return true;
}

}
}

How to validate 2 field with OR condition?

You need to create custom validator to validate multiple fields.

create a custom annotation:

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;

@Documented
@Constraint(validatedBy = CarRequestValidator.class)
@Target({ ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestAnnotation {
String message() default "{RequestAnnotation}";

Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};
}

create a custom validator:

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class CarRequestValidator implements
ConstraintValidator<RequestAnnotation, CarRequest> {

@Override
public void initialize(RequestAnnotation constraintAnnotation) {

}

@Override
public boolean isValid(CarRequest value, ConstraintValidatorContext context) {
// validation logic goes here
return false;
}
}

Now, annotate your model with custom annotation:

@RequestAnnotation 
public class CarRequest {
private String customerName;
private String customerId;
}

How to efficiently validate multiple input fields in a form

The ideal solution here would be to set the required attribute on each input and let the browser handle the validation for you.

If you’d prefer a JS method instead, read on.


How about using some array manipulation like this:

function isFormIncomplete(formName, fieldNames) {
const form = document.forms[formName];
return fieldNames.some(field => !form[field].value);
}

isFormIncomplete(['fname', 'lname', 'age']);

This function starts with an array of field names (['fname', 'lname', 'age']) which is reduced using some(). This function returns true if the predicate function (field => !form[field].value) returns true for at least one element in the array. In this case, the predicate returns true if there is no value, so the result of some() is true if any field is empty.

Struts: Validate two fields at once

The validation of two or more fields too easy if you use ValidatorForm and validate method.

To use declarative custom validator you need to read this reference guide that has links and example of custom validator to validate two fields.

This is an example of how you could compare two fields to see if they have the same value. A good example of this is when you are validating a user changing their password and there is the main password field and a confirmation field.

<validator name="twofields"
classname="com.mysite.StrutsValidator"
method="validateTwoFields"
msg="errors.twofields"/>

<field property="password"
depends="required,twofields">
<arg position="0" key="typeForm.password.displayname"/>
<var>
<var-name>secondProperty</var-name>
<var-value>password2</var-value>
</var>
</field>
public class CustomValidator {

// ------------------------------------------------------------ Constructors

/**
* Constructor for CustomValidator.
*/
public CustomValidator() {
super();
}

// ---------------------------------------------------------- Public Methods

/**
* Example validator for comparing the equality of two fields
*
* http://struts.apache.org/userGuide/dev_validator.html
* http://www.raibledesigns.com/page/rd/20030226
*/
public static boolean validateTwoFields(
Object bean,
ValidatorAction va,
Field field,
ActionMessages errors,
HttpServletRequest request) {

String value =
ValidatorUtils.getValueAsString(bean, field.getProperty());
String property2 = field.getVarValue("secondProperty");
String value2 = ValidatorUtils.getValueAsString(bean, property2);

if (!GenericValidator.isBlankOrNull(value)) {
try {
if (!value.equals(value2)) {
errors.add(
field.getKey(),
Resources.getActionMessage(request, va, field));

return false;
}
} catch (Exception e) {
errors.add(
field.getKey(),
Resources.getActionMessage(request, va, field));
return false;
}
}
return true;
}

}

Validate two fields of struct with OR condition in Golang

With more recent versions of the validator package (e.g. v9 onward) you can use required_without tag.

The field under validation must be present and not empty only when any of the other specified fields are not present. For strings ensures value is not "". For slices, maps, pointers, interfaces, channels and functions ensures the value is not nil.

type man struct {
Numbers []int `json:"numbers" validate:"required_without=Pass"`
Pass bool `json:"pass"`
}

Testing with different inputs:

man{}
man{nil, false}
man{nil, true}
man{[]int{}, false}

Gives:

Key: 'man.Numbers' Error:Field validation for 'Numbers' failed on the 'required_without' tag
Key: 'man.Numbers' Error:Field validation for 'Numbers' failed on the 'required_without' tag
pass
pass

Unfortunately with v2 you can only implement single field validation, so you don't really have a nice and straightforward way to access the parent struct. You might have to wrap the struct in another struct to consider man as a field.

type wrapper struct {
man man `validate:"man"`
}

// Very simple validation func
func manValidator(v interface{}, param string) error {
m := v.(man)
if m.Numbers != nil || m.Pass {
return nil
}
return errors.New("validation failed")
}

func main() {
validate.SetValidationFunc("man", manValidator)
validator.Validate(wrapper{man{}})
}


Related Topics



Leave a reply



Submit