Skip to content

Commit

Permalink
Add public method validateBbanEntry to BbanStructure for BBAN entry v…
Browse files Browse the repository at this point in the history
…alidation by country (#156)

* Add public method validateBbanEntry to BbanStructure for BBAN entry validation by country

* Fix formatting
  • Loading branch information
PabloLec authored Dec 28, 2024
1 parent 8c0c0c3 commit e13e5f7
Show file tree
Hide file tree
Showing 4 changed files with 412 additions and 41 deletions.
1 change: 1 addition & 0 deletions src/main/java/org/iban4j/IbanFormatException.java
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ public static enum IbanFormatViolation {
COUNTRY_CODE_NOT_NULL,

BBAN_LENGTH,
BBAN_INVALID_ENTRY_TYPE,
BBAN_ONLY_DIGITS,
BBAN_ONLY_UPPER_CASE_LETTERS,
BBAN_ONLY_DIGITS_OR_LETTERS,
Expand Down
46 changes: 5 additions & 41 deletions src/main/java/org/iban4j/IbanUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,6 @@ public final class IbanUtil {
private static final int CHECK_DIGIT_LENGTH = 2;
private static final int BBAN_INDEX = CHECK_DIGIT_INDEX + CHECK_DIGIT_LENGTH;

private static final String ASSERT_UPPER_LETTERS = "[%s] must contain only upper case letters.";
private static final String ASSERT_DIGITS_AND_LETTERS = "[%s] must contain only digits or letters.";
private static final String ASSERT_DIGITS = "[%s] must contain only digits.";

private IbanUtil() {
}

Expand Down Expand Up @@ -398,49 +394,17 @@ private static void validateBbanLength(final String iban,
private static void validateBbanEntries(final String iban,
final BbanStructure structure) {
final String bban = getBban(iban);
final CountryCode countryCode = CountryCode.getByCode(getCountryCode(iban));
int bbanEntryOffset = 0;
for(final BbanStructureEntry entry : structure.getEntries()) {

for (final BbanStructureEntry entry : structure.getEntries()) {
final int entryLength = entry.getLength();
final String entryValue = bban.substring(bbanEntryOffset,
bbanEntryOffset + entryLength);

bbanEntryOffset = bbanEntryOffset + entryLength;

// validate character type
validateBbanEntryCharacterType(entry, entryValue);
}
}
bbanEntryOffset += entryLength;

private static void validateBbanEntryCharacterType(final BbanStructureEntry entry,
final String entryValue) {
switch (entry.getCharacterType()) {
case a:
for(char ch: entryValue.toCharArray()) {
if(!Character.isUpperCase(ch)) {
throw new IbanFormatException(BBAN_ONLY_UPPER_CASE_LETTERS,
entry.getEntryType(), entryValue, ch,
String.format(ASSERT_UPPER_LETTERS, entryValue));
}
}
break;
case c:
for(char ch: entryValue.toCharArray()) {
if(!Character.isLetterOrDigit(ch)) {
throw new IbanFormatException(BBAN_ONLY_DIGITS_OR_LETTERS,
entry.getEntryType(), entryValue, ch,
String.format(ASSERT_DIGITS_AND_LETTERS, entryValue));
}
}
break;
case n:
for(char ch: entryValue.toCharArray()) {
if(!Character.isDigit(ch)) {
throw new IbanFormatException(BBAN_ONLY_DIGITS,
entry.getEntryType(), entryValue, ch,
String.format(ASSERT_DIGITS, entryValue));
}
}
break;
BbanStructure.validateBbanEntry(countryCode, entry.getEntryType(), entryValue);
}
}

Expand Down
95 changes: 95 additions & 0 deletions src/main/java/org/iban4j/bban/BbanStructure.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,19 @@
import java.util.List;
import java.util.Optional;
import org.iban4j.CountryCode;
import org.iban4j.IbanFormatException;
import org.iban4j.UnsupportedCountryException;

import static org.iban4j.IbanFormatException.IbanFormatViolation.*;

/** Class that represents BBAN structure */
public class BbanStructure {

private static final String INVALID_ENTRY_TYPE = "Entry type [%s] does not exist for country [%s]";
private static final String ASSERT_UPPER_LETTERS = "[%s] must contain only upper case letters.";
private static final String ASSERT_DIGITS_AND_LETTERS = "[%s] must contain only digits or letters.";
private static final String ASSERT_DIGITS = "[%s] must contain only digits.";

private static final EnumMap<CountryCode, BbanStructure> structures;

/**
Expand Down Expand Up @@ -657,4 +666,90 @@ public int getBbanLength() {

return length;
}

/**
* Validates a specific BBAN entry based on the country code, entry type, and value.
*
* @param countryCode the country code for which the validation should be performed.
* @param entryType the type of the BBAN entry (e.g., bank code, branch code).
* @param entryValue the value of the BBAN entry to validate.
* @throws UnsupportedCountryException if country is not supported.
* @throws IbanFormatException if the entry type does not exist for the given country or if the entry value is invalid.
*/
public static void validateBbanEntry(final CountryCode countryCode,
final BbanEntryType entryType,
final String entryValue) {
final BbanStructure bbanStructure = forCountry(countryCode);

if (bbanStructure == null) {
throw new UnsupportedCountryException(countryCode.toString(),
String.format("Country code [%s] is not supported.", countryCode));
}

final BbanStructureEntry entry = bbanStructure.getEntries().stream()
.filter(e -> e.getEntryType().equals(entryType))
.findFirst()
.orElseThrow(() -> new IbanFormatException(BBAN_INVALID_ENTRY_TYPE,
String.format(INVALID_ENTRY_TYPE,
entryType.name(), countryCode)));

validateBbanEntryLength(entry, entryValue);
validateBbanEntryCharacterType(entry, entryValue);
}

/**
* Validates the length of a BBAN entry value.
*
* @param entry the BBAN structure entry defining the expected length.
* @param entryValue the value of the BBAN entry to validate.
* @throws IbanFormatException if the entry value length is incorrect.
*/
private static void validateBbanEntryLength(final BbanStructureEntry entry,
final String entryValue) {
if (entryValue.length() != entry.getLength()) {
throw new IbanFormatException(BBAN_LENGTH,
String.format("Entry value [%s] must be exactly %d characters long.",
entryValue, entry.getLength()));
}
}

/**
* Validates the character type of BBAN entry value.
*
* @param entry the BBAN structure entry defining the expected character type.
* @param entryValue the value of the BBAN entry to validate.
* @throws IbanFormatException if the entry value contains invalid characters.
*/
private static void validateBbanEntryCharacterType(final BbanStructureEntry entry,
final String entryValue) {
switch (entry.getCharacterType()) {
case a:
for (char ch: entryValue.toCharArray()) {
if (!Character.isUpperCase(ch)) {
throw new IbanFormatException(BBAN_ONLY_UPPER_CASE_LETTERS,
entry.getEntryType(), entryValue, ch,
String.format(ASSERT_UPPER_LETTERS, entryValue));
}
}
break;
case c:
for (char ch: entryValue.toCharArray()) {
if (!Character.isLetterOrDigit(ch)) {
throw new IbanFormatException(BBAN_ONLY_DIGITS_OR_LETTERS,
entry.getEntryType(), entryValue, ch,
String.format(ASSERT_DIGITS_AND_LETTERS, entryValue));
}
}
break;
case n:
for (char ch: entryValue.toCharArray()) {
if (!Character.isDigit(ch)) {
throw new IbanFormatException(BBAN_ONLY_DIGITS,
entry.getEntryType(), entryValue, ch,
String.format(ASSERT_DIGITS, entryValue));
}
}
break;
}
}
}
Loading

0 comments on commit e13e5f7

Please sign in to comment.