diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 6828fb1c0..59c6d67ba 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -64,6 +64,7 @@ The type attribute can be add,update,fix,remove. + IBANValidator.setValidator() preserves unrelated secondary country codes when changing an alias. Drop the symbol separator in the currency and percent re-parse (#430). Count unpaired carriage returns in adjustForLineEnding (#431). Validate path, query and fragment for authority-less file URLs (#432). diff --git a/src/main/java/org/apache/commons/validator/routines/IBANValidator.java b/src/main/java/org/apache/commons/validator/routines/IBANValidator.java index 3052fb09f..9bd8762f4 100644 --- a/src/main/java/org/apache/commons/validator/routines/IBANValidator.java +++ b/src/main/java/org/apache/commons/validator/routines/IBANValidator.java @@ -360,6 +360,25 @@ public boolean isValid(final String code) { return validate(code) == IBANValidatorStatus.VALID; } + /** + * Removes the other country codes of a validator that was replaced or removed under the given country code. + *

+ * Nothing is removed when the country code was one of the other country codes of the previous validator (for example + * AX for FI), since the previous validator remains installed under its own country code. Only entries that still map to + * the previous validator are removed, so other country codes that have since been given their own validator are kept. + *

+ * + * @param countryCode The country code that was replaced or removed. + * @param prev The validator previously installed for the country code, may be null. + */ + private void removeOtherCountryCodes(final String countryCode, final Validator prev) { + if (prev != null && prev.countryCode.equals(countryCode)) { + for (final String otherCC : prev.otherCountryCodes) { + validatorMap.remove(otherCC, prev); + } + } + } + /** * Installs a validator. Will replace any existing entry which has the same countryCode. * @@ -376,11 +395,7 @@ public Validator setValidator(final String countryCode, final int length, final } if (length < 0) { final Validator prev = validatorMap.remove(countryCode); - if (prev != null) { - for (final String otherCC : prev.otherCountryCodes) { - validatorMap.remove(otherCC); - } - } + removeOtherCountryCodes(countryCode, prev); return prev; } return setValidator(new Validator(countryCode, length, format)); @@ -398,11 +413,7 @@ public Validator setValidator(final Validator validator) { throw new IllegalStateException("The singleton validator cannot be modified"); } final Validator prev = validatorMap.put(validator.countryCode, validator); - if (prev != null) { - for (final String otherCC : prev.otherCountryCodes) { - validatorMap.remove(otherCC); - } - } + removeOtherCountryCodes(validator.countryCode, prev); for (final String otherCC : validator.otherCountryCodes) { validatorMap.put(otherCC, validator); } diff --git a/src/test/java/org/apache/commons/validator/routines/IBANValidatorTest.java b/src/test/java/org/apache/commons/validator/routines/IBANValidatorTest.java index 95c908984..7ca2ff42a 100644 --- a/src/test/java/org/apache/commons/validator/routines/IBANValidatorTest.java +++ b/src/test/java/org/apache/commons/validator/routines/IBANValidatorTest.java @@ -513,6 +513,37 @@ void testSetValidatorReplaceOtherCountryCodes() { assertFalse(validator.hasValidator("IM")); } + @Test + void testSetValidatorForOtherCountryCode() { + final IBANValidator validator = new IBANValidator(); + // AX (Aland Islands) is handled by the FI (Finland) validator by default + assertEquals(validator.getValidator("FI"), validator.getValidator("AX")); + // Give AX its own validator + final Validator axValidator = new Validator("AX", 18, "AX\\d{16}"); + assertEquals(validator.getValidator("FI"), validator.setValidator(axValidator)); + assertEquals(axValidator, validator.getValidator("AX")); + assertTrue(validator.isValid("AX2112345600000785")); + assertTrue(validator.isValid("FI2112345600000785")); + // Replacing FI must not remove the AX validator, which no longer belongs to FI + validator.setValidator(new Validator("FI", 18, "FI\\d{16}")); + assertEquals(axValidator, validator.getValidator("AX")); + } + + @Test + void testSetValidatorRemoveOtherCountryCode() { + final IBANValidator validator = new IBANValidator(); + // GF (French Guiana) and GP (Guadeloupe) are handled by the FR (France) validator by default + final Validator frValidator = validator.getValidator("FR"); + assertEquals(frValidator, validator.getValidator("GF")); + assertEquals(frValidator, validator.getValidator("GP")); + // Removing GF must only remove GF + assertEquals(frValidator, validator.setValidator("GF", -1, null)); + assertFalse(validator.hasValidator("GF")); + assertEquals(frValidator, validator.getValidator("FR")); + assertEquals(frValidator, validator.getValidator("GP")); + assertTrue(validator.isValid("GP1120041010050500013M02606")); + } + @Test void testSorted() { final IBANValidator validator = new IBANValidator();