Noremac
Noremac

Reputation: 3547

How can I map a class level validation to a specific field?

I have a class level validation like so:

@PostalCodeValidForCountry
public class Address
{
  ...
  private String postalCode;
  private String country;
}

The validation is implemented like so:

@Override
public boolean isValid(Address address, ConstraintValidatorContext constraintContext)
{
    String postalCode = address.getPostalCode();
    String country = address.getCountry();
    String regex = null;
    if (null == country || Address.COUNTRY_USA.equals(country))
    {
        regex = "^[0-9]{5}$";
    }
    else if (Address.COUNTRY_CANADA.equals(country))
    {
        regex = "^[A-Za-z][0-9][A-Za-z] [0-9][A-Za-z][0-9]$";
    }

    Pattern postalPattern = Pattern.compile(regex);
    Matcher matcher = postalPattern.matcher(postalCode);
    if (matcher.matches())
    {
        return true;
    }

    return false;
}

Currently when I get the BindingResult the error that results from a failed validation is an ObjectError on with the objectName of Address. I'd like to however, map this error to the postalCode field instead. So instead of reporting an ObjectError, I'd like to report a FieldError with a fieldName of postalCode.

Is it possible to do this within the custom validation itself?

Upvotes: 1

Views: 265

Answers (1)

Alishazy
Alishazy

Reputation: 66

I hope what you are looking for is this:

constraintContext.buildConstraintViolationWithTemplate("custom_error_code").addNode("postalCode").addConstraintViolation();

This is how your modified method will look like:

@Override
public boolean isValid(Address address, ConstraintValidatorContext constraintContext)
{
    String postalCode = address.getPostalCode();
    String country = address.getCountry();
    String regex = null;
    if (null == country || Address.COUNTRY_USA.equals(country))
    {
        regex = "^[0-9]{5}$";
    }
    else if (Address.COUNTRY_CANADA.equals(country))
    {
      regex = "^[A-Za-z][0-9][A-Za-z] [0-9][A-Za-z][0-9]$";
    }

  Pattern postalPattern = Pattern.compile(regex);
  Matcher matcher = postalPattern.matcher(postalCode);
  if (matcher.matches())
  {
    return true;
  }

  // this will generate a field error for "postalCode" field.
  constraintContext.disableDefaultConstraintViolation();
  constraintContext.buildConstraintViolationWithTemplate("custom_error_code").addNode("postalCode").addConstraintViolation();

    return false;
}

Just remember, you will see this FieldError in BindingResult object only if your "isValid" method will return false.

Upvotes: 3

Related Questions