de.schegge.bank.validator.IbanValidator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bank-account-validator Show documentation
Show all versions of bank-account-validator Show documentation
Validation Annotations for IBAN and BIC
The newest version!
package de.schegge.bank.validator;
import de.schegge.bank.BankService;
import de.schegge.bank.IbanLocale;
import de.schegge.bank.validator.IBAN.IbanType;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import java.math.BigInteger;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class IbanValidator implements ConstraintValidator {
public static final Pattern PATTERN = Pattern.compile("([A-Z]{2})(\\d{2})([A-Z0-9]{11,30})");
private static final BigInteger VALUE_97 = BigInteger.valueOf(97);
private static final int[] CHAR_VALUES = charValues();
private Check check;
private IbanType type;
private static int[] charValues() {
String characterValues = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int[] result = new int['Z' + 1];
for (int i = 0; i < characterValues.length(); i++) {
result[characterValues.charAt(i)] = i;
}
return result;
}
@Override
public void initialize(IBAN constraintAnnotation) {
check = constraintAnnotation.check();
type = constraintAnnotation.type();
}
@Override
public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
if (value == null) {
return true;
}
Matcher matcher = PATTERN.matcher(value);
if (!matcher.matches()) {
return false;
}
String countryCode = matcher.group(1);
int checkDigit = Integer.parseInt(matcher.group(2));
String basicBankAccountNumber = matcher.group(3);
if (isValidChecksum(countryCode, basicBankAccountNumber, checkDigit)) {
return false;
}
IbanLocale ibanLocale = IbanLocale.byCode(countryCode);
if (ibanLocale == null) {
return check == Check.LENIENT;
}
if (type == IbanType.SEPA && !IbanLocale.allSepaIbanLocales().contains(ibanLocale)) {
return false;
}
if (type == IbanType.NO_SEPA && IbanLocale.allSepaIbanLocales().contains(ibanLocale)) {
return false;
}
if (basicBankAccountNumber.length() != ibanLocale.getLength() - 4) {
return false;
}
if (check == Check.LENIENT) {
return true;
}
Optional bankService = BankService.byCountry(countryCode);
if (bankService.isEmpty()) {
return check == Check.PRAGMATIC;
}
return bankService.map(x -> x.byBasicBankAcountNumber(basicBankAccountNumber)).isPresent();
}
private static boolean isValidChecksum(String countryCode, String basicBankAccountNumber, int checkDigit) {
StringBuilder builder = new StringBuilder(basicBankAccountNumber.length());
basicBankAccountNumber.chars().mapToObj(c -> CHAR_VALUES[c]).map(String::valueOf).forEach(builder::append);
countryCode.chars().mapToObj(c -> CHAR_VALUES[c]).map(String::valueOf).forEach(builder::append);
return checkDigit != 98 - new BigInteger(builder.append("00").toString()).mod(VALUE_97).intValue();
}
}