Skip to content

Commit 6b42243

Browse files
committed
8353713: Improve Currency.getInstance exception handling
Backport-of: 5cac579619164b9a664327a4f71c4de7e7575276
1 parent ed57c7c commit 6b42243

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
@@ -319,8 +319,8 @@ private static Currency getInstance(String currencyCode, int defaultFractionDigi
319319
// or in the list of other currencies.
320320
boolean found = false;
321321
if (currencyCode.length() != 3) {
322-
throw new IllegalArgumentException("The input currency code must " +
323-
"have a length of 3 characters");
322+
throw new IllegalArgumentException(
323+
"The input currency code: \"%s\" must have a length of 3 characters".formatted(currencyCode));
324324
}
325325
char char1 = currencyCode.charAt(0);
326326
char char2 = currencyCode.charAt(1);
@@ -343,8 +343,8 @@ private static Currency getInstance(String currencyCode, int defaultFractionDigi
343343
if (!found) {
344344
OtherCurrencyEntry ocEntry = OtherCurrencyEntry.findEntry(currencyCode);
345345
if (ocEntry == null) {
346-
throw new IllegalArgumentException("The input currency code" +
347-
" is not a valid ISO 4217 code");
346+
throw new IllegalArgumentException(
347+
"The input currency code: \"%s\" is not a valid ISO 4217 code".formatted(currencyCode));
348348
}
349349
defaultFractionDigits = ocEntry.fraction;
350350
numericCode = ocEntry.numericCode;
@@ -399,8 +399,8 @@ public static Currency getInstance(Locale locale) {
399399
String country = CalendarDataUtility.findRegionOverride(locale).getCountry();
400400

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

406406
char char1 = country.charAt(0);
@@ -417,8 +417,8 @@ public static Currency getInstance(Locale locale) {
417417
} else {
418418
// special cases
419419
if (tableEntry == INVALID_COUNTRY_ENTRY) {
420-
throw new IllegalArgumentException("The country of the input locale" +
421-
" is not a valid ISO 3166 country code");
420+
throw new IllegalArgumentException(
421+
"The country of the input locale: \"%s\" is not a valid ISO 3166 country code".formatted(locale));
422422
}
423423
if (tableEntry == COUNTRY_WITHOUT_CURRENCY_ENTRY) {
424424
return null;
@@ -683,8 +683,8 @@ private Object readResolve() {
683683
*/
684684
private static int getMainTableEntry(char char1, char char2) {
685685
if (char1 < 'A' || char1 > 'Z' || char2 < 'A' || char2 > 'Z') {
686-
throw new IllegalArgumentException("The country code is not a " +
687-
"valid ISO 3166 code");
686+
throw new IllegalArgumentException(
687+
"The country code: \"%c%c\" is not a valid ISO 3166 code".formatted(char1, char2));
688688
}
689689
return mainTable[(char1 - 'A') * A_TO_Z + (char2 - 'A')];
690690
}
@@ -695,8 +695,8 @@ private static int getMainTableEntry(char char1, char char2) {
695695
*/
696696
private static void setMainTableEntry(char char1, char char2, int entry) {
697697
if (char1 < 'A' || char1 > 'Z' || char2 < 'A' || char2 > 'Z') {
698-
throw new IllegalArgumentException("The country code is not a " +
699-
"valid ISO 3166 code");
698+
throw new IllegalArgumentException(
699+
"The country code: \"%c%c\" is not a valid ISO 3166 code".formatted(char1, char2));
700700
}
701701
mainTable[(char1 - 'A') * A_TO_Z + (char2 - 'A')] = entry;
702702
}

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,13 +190,15 @@ 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
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
187-
()-> Currency.getInstance(Locale.of("", "EU")), "Did not throw IAE");
188-
assertEquals("The country of the input locale is not a valid" +
189-
" ISO 3166 country code", ex.getMessage());
199+
()-> Currency.getInstance(loc), "Did not throw IAE");
200+
assertEquals("The country of the input locale: \"%s\" is not a valid ISO 3166 country code"
201+
.formatted(loc), ex.getMessage());
190202
}
191203

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

0 commit comments

Comments
 (0)