Skip to content

Commit 4264639

Browse files
committed
8353713: Improve Currency.getInstance exception handling
Reviewed-by: mbaesken Backport-of: 5cac579619164b9a664327a4f71c4de7e7575276
1 parent 0826b18 commit 4264639

File tree

2 files changed

+37
-25
lines changed

2 files changed

+37
-25
lines changed

src/java.base/share/classes/java/util/Currency.java

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -314,8 +314,8 @@ private static Currency getInstance(String currencyCode, int defaultFractionDigi
314314
// or in the list of other currencies.
315315
boolean found = false;
316316
if (currencyCode.length() != 3) {
317-
throw new IllegalArgumentException("The input currency code must " +
318-
"have a length of 3 characters");
317+
throw new IllegalArgumentException(
318+
"The input currency code: \"%s\" must have a length of 3 characters".formatted(currencyCode));
319319
}
320320
char char1 = currencyCode.charAt(0);
321321
char char2 = currencyCode.charAt(1);
@@ -338,8 +338,8 @@ private static Currency getInstance(String currencyCode, int defaultFractionDigi
338338
if (!found) {
339339
OtherCurrencyEntry ocEntry = OtherCurrencyEntry.findEntry(currencyCode);
340340
if (ocEntry == null) {
341-
throw new IllegalArgumentException("The input currency code" +
342-
" is not a valid ISO 4217 code");
341+
throw new IllegalArgumentException(
342+
"The input currency code: \"%s\" is not a valid ISO 4217 code".formatted(currencyCode));
343343
}
344344
defaultFractionDigits = ocEntry.fraction;
345345
numericCode = ocEntry.numericCode;
@@ -394,8 +394,8 @@ public static Currency getInstance(Locale locale) {
394394
String country = CalendarDataUtility.findRegionOverride(locale).getCountry();
395395

396396
if (country == null || !country.matches("^[a-zA-Z]{2}$")) {
397-
throw new IllegalArgumentException("The country of the input locale" +
398-
" is not a valid ISO 3166 country code");
397+
throw new IllegalArgumentException(
398+
"The country of the input locale: \"%s\" is not a valid ISO 3166 country code".formatted(locale));
399399
}
400400

401401
char char1 = country.charAt(0);
@@ -412,8 +412,8 @@ public static Currency getInstance(Locale locale) {
412412
} else {
413413
// special cases
414414
if (tableEntry == INVALID_COUNTRY_ENTRY) {
415-
throw new IllegalArgumentException("The country of the input locale" +
416-
" is not a valid ISO 3166 country code");
415+
throw new IllegalArgumentException(
416+
"The country of the input locale: \"%s\" is not a valid ISO 3166 country code".formatted(locale));
417417
}
418418
if (tableEntry == COUNTRY_WITHOUT_CURRENCY_ENTRY) {
419419
return null;
@@ -678,8 +678,8 @@ private Object readResolve() {
678678
*/
679679
private static int getMainTableEntry(char char1, char char2) {
680680
if (char1 < 'A' || char1 > 'Z' || char2 < 'A' || char2 > 'Z') {
681-
throw new IllegalArgumentException("The country code is not a " +
682-
"valid ISO 3166 code");
681+
throw new IllegalArgumentException(
682+
"The country code: \"%c%c\" is not a valid ISO 3166 code".formatted(char1, char2));
683683
}
684684
return mainTable[(char1 - 'A') * A_TO_Z + (char2 - 'A')];
685685
}
@@ -690,8 +690,8 @@ private static int getMainTableEntry(char char1, char char2) {
690690
*/
691691
private static void setMainTableEntry(char char1, char char2, int entry) {
692692
if (char1 < 'A' || char1 > 'Z' || char2 < 'A' || char2 > 'Z') {
693-
throw new IllegalArgumentException("The country code is not a " +
694-
"valid ISO 3166 code");
693+
throw new IllegalArgumentException(
694+
"The country code: \"%c%c\" is not a valid ISO 3166 code".formatted(char1, char2));
695695
}
696696
mainTable[(char1 - 'A') * A_TO_Z + (char2 - 'A')] = entry;
697697
}

test/jdk/java/util/Currency/CurrencyTest.java

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -25,7 +25,7 @@
2525
* @test
2626
* @bug 4290801 4692419 4693631 5101540 5104960 6296410 6336600 6371531
2727
* 6488442 7036905 8008577 8039317 8074350 8074351 8150324 8167143
28-
* 8264792 8334653
28+
* 8264792 8334653 8353713
2929
* @summary Basic tests for Currency class.
3030
* @modules java.base/java.util:open
3131
* jdk.localedata
@@ -84,23 +84,33 @@ private static Stream<String> validCurrencies() {
8484
public void invalidCurrencyTest(String currencyCode) {
8585
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () ->
8686
Currency.getInstance(currencyCode), "getInstance() did not throw IAE");
87-
assertEquals("The input currency code is not a" +
88-
" valid ISO 4217 code", ex.getMessage());
87+
assertEquals("The input currency code: \"%s\" is not a valid ISO 4217 code"
88+
.formatted(currencyCode), ex.getMessage());
8989
}
9090

9191
private static Stream<String> non4217Currencies() {
9292
return Stream.of("AQD", "US$");
9393
}
9494

95+
// Provide 3 length code, but first 2 chars should not be able to index
96+
// the main table, thus resulting as incorrect country code
97+
@Test
98+
void invalidCountryInCodeTest() {
99+
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () ->
100+
Currency.getInstance("..A"), "getInstance() did not throw IAE");
101+
assertEquals("The country code: \"%s\" is not a valid ISO 3166 code"
102+
.formatted(".."), ex.getMessage());
103+
}
104+
95105
// Calling getInstance() with a currency code not 3 characters long should throw
96106
// an IAE
97107
@ParameterizedTest
98108
@MethodSource("invalidLengthCurrencies")
99109
public void invalidCurrencyLengthTest(String currencyCode) {
100110
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () ->
101111
Currency.getInstance(currencyCode), "getInstance() did not throw IAE");
102-
assertEquals("The input currency code must have a length of 3" +
103-
" characters", ex.getMessage());
112+
assertEquals("The input currency code: \"%s\" must have a length of 3 characters"
113+
.formatted(currencyCode), ex.getMessage());
104114
}
105115

106116
private static Stream<String> invalidLengthCurrencies() {
@@ -163,8 +173,8 @@ public void localeMappingTest() {
163173
"AC|CP|DG|EA|EU|FX|IC|SU|TA|UK")) { // exceptional reservation codes
164174
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
165175
() -> Currency.getInstance(locale), "Did not throw IAE");
166-
assertEquals("The country of the input locale is not a" +
167-
" valid ISO 3166 country code", ex.getMessage());
176+
assertEquals("The country of the input locale: \"%s\" is not a valid ISO 3166 country code"
177+
.formatted(locale), ex.getMessage());
168178
} else {
169179
goodCountries++;
170180
Currency currency = Currency.getInstance(locale);
@@ -180,14 +190,16 @@ public void localeMappingTest() {
180190
}
181191
}
182192

183-
// Check an invalid country code
193+
// Check an invalid country code supplied via the region override
184194
@Test
185-
public void invalidCountryTest() {
195+
public void invalidCountryRegionOverrideTest() {
196+
// Override US with nonsensical country
197+
var loc = Locale.forLanguageTag("en-US-u-rg-XXzzzz");
186198
Locale l = new Locale("", "EU");
187199
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
188-
()-> Currency.getInstance(l), "Did not throw IAE");
189-
assertEquals("The country of the input locale is not a valid" +
190-
" ISO 3166 country code", ex.getMessage());
200+
()-> Currency.getInstance(loc), "Did not throw IAE");
201+
assertEquals("The country of the input locale: \"%s\" is not a valid ISO 3166 country code"
202+
.formatted(loc), ex.getMessage());
191203
}
192204

193205
// Ensure a selection of countries have the expected currency

0 commit comments

Comments
 (0)