From fa1c47c01b5711dd6cfbb52cc80af5c13c6976ae Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Tue, 15 Jul 2025 14:10:04 +0200 Subject: [PATCH] backport 5cac579619164b9a664327a4f71c4de7e7575276 --- .../share/classes/java/util/Currency.java | 24 ++++++------ test/jdk/java/util/Currency/CurrencyTest.java | 38 ++++++++++++------- 2 files changed, 37 insertions(+), 25 deletions(-) diff --git a/src/java.base/share/classes/java/util/Currency.java b/src/java.base/share/classes/java/util/Currency.java index 31d21156aeb..d256433d850 100644 --- a/src/java.base/share/classes/java/util/Currency.java +++ b/src/java.base/share/classes/java/util/Currency.java @@ -314,8 +314,8 @@ private static Currency getInstance(String currencyCode, int defaultFractionDigi // or in the list of other currencies. boolean found = false; if (currencyCode.length() != 3) { - throw new IllegalArgumentException("The input currency code must " + - "have a length of 3 characters"); + throw new IllegalArgumentException( + "The input currency code: \"%s\" must have a length of 3 characters".formatted(currencyCode)); } char char1 = currencyCode.charAt(0); char char2 = currencyCode.charAt(1); @@ -338,8 +338,8 @@ private static Currency getInstance(String currencyCode, int defaultFractionDigi if (!found) { OtherCurrencyEntry ocEntry = OtherCurrencyEntry.findEntry(currencyCode); if (ocEntry == null) { - throw new IllegalArgumentException("The input currency code" + - " is not a valid ISO 4217 code"); + throw new IllegalArgumentException( + "The input currency code: \"%s\" is not a valid ISO 4217 code".formatted(currencyCode)); } defaultFractionDigits = ocEntry.fraction; numericCode = ocEntry.numericCode; @@ -394,8 +394,8 @@ public static Currency getInstance(Locale locale) { String country = CalendarDataUtility.findRegionOverride(locale).getCountry(); if (country == null || !country.matches("^[a-zA-Z]{2}$")) { - throw new IllegalArgumentException("The country of the input locale" + - " is not a valid ISO 3166 country code"); + throw new IllegalArgumentException( + "The country of the input locale: \"%s\" is not a valid ISO 3166 country code".formatted(locale)); } char char1 = country.charAt(0); @@ -412,8 +412,8 @@ public static Currency getInstance(Locale locale) { } else { // special cases if (tableEntry == INVALID_COUNTRY_ENTRY) { - throw new IllegalArgumentException("The country of the input locale" + - " is not a valid ISO 3166 country code"); + throw new IllegalArgumentException( + "The country of the input locale: \"%s\" is not a valid ISO 3166 country code".formatted(locale)); } if (tableEntry == COUNTRY_WITHOUT_CURRENCY_ENTRY) { return null; @@ -678,8 +678,8 @@ private Object readResolve() { */ private static int getMainTableEntry(char char1, char char2) { if (char1 < 'A' || char1 > 'Z' || char2 < 'A' || char2 > 'Z') { - throw new IllegalArgumentException("The country code is not a " + - "valid ISO 3166 code"); + throw new IllegalArgumentException( + "The country code: \"%c%c\" is not a valid ISO 3166 code".formatted(char1, char2)); } return mainTable[(char1 - 'A') * A_TO_Z + (char2 - 'A')]; } @@ -690,8 +690,8 @@ private static int getMainTableEntry(char char1, char char2) { */ private static void setMainTableEntry(char char1, char char2, int entry) { if (char1 < 'A' || char1 > 'Z' || char2 < 'A' || char2 > 'Z') { - throw new IllegalArgumentException("The country code is not a " + - "valid ISO 3166 code"); + throw new IllegalArgumentException( + "The country code: \"%c%c\" is not a valid ISO 3166 code".formatted(char1, char2)); } mainTable[(char1 - 'A') * A_TO_Z + (char2 - 'A')] = entry; } diff --git a/test/jdk/java/util/Currency/CurrencyTest.java b/test/jdk/java/util/Currency/CurrencyTest.java index 179d1f61a05..16c329ef535 100644 --- a/test/jdk/java/util/Currency/CurrencyTest.java +++ b/test/jdk/java/util/Currency/CurrencyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @bug 4290801 4692419 4693631 5101540 5104960 6296410 6336600 6371531 * 6488442 7036905 8008577 8039317 8074350 8074351 8150324 8167143 - * 8264792 8334653 + * 8264792 8334653 8353713 * @summary Basic tests for Currency class. * @modules java.base/java.util:open * jdk.localedata @@ -84,14 +84,24 @@ private static Stream validCurrencies() { public void invalidCurrencyTest(String currencyCode) { IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> Currency.getInstance(currencyCode), "getInstance() did not throw IAE"); - assertEquals("The input currency code is not a" + - " valid ISO 4217 code", ex.getMessage()); + assertEquals("The input currency code: \"%s\" is not a valid ISO 4217 code" + .formatted(currencyCode), ex.getMessage()); } private static Stream non4217Currencies() { return Stream.of("AQD", "US$"); } + // Provide 3 length code, but first 2 chars should not be able to index + // the main table, thus resulting as incorrect country code + @Test + void invalidCountryInCodeTest() { + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> + Currency.getInstance("..A"), "getInstance() did not throw IAE"); + assertEquals("The country code: \"%s\" is not a valid ISO 3166 code" + .formatted(".."), ex.getMessage()); + } + // Calling getInstance() with a currency code not 3 characters long should throw // an IAE @ParameterizedTest @@ -99,8 +109,8 @@ private static Stream non4217Currencies() { public void invalidCurrencyLengthTest(String currencyCode) { IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> Currency.getInstance(currencyCode), "getInstance() did not throw IAE"); - assertEquals("The input currency code must have a length of 3" + - " characters", ex.getMessage()); + assertEquals("The input currency code: \"%s\" must have a length of 3 characters" + .formatted(currencyCode), ex.getMessage()); } private static Stream invalidLengthCurrencies() { @@ -163,8 +173,8 @@ public void localeMappingTest() { "AC|CP|DG|EA|EU|FX|IC|SU|TA|UK")) { // exceptional reservation codes IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> Currency.getInstance(locale), "Did not throw IAE"); - assertEquals("The country of the input locale is not a" + - " valid ISO 3166 country code", ex.getMessage()); + assertEquals("The country of the input locale: \"%s\" is not a valid ISO 3166 country code" + .formatted(locale), ex.getMessage()); } else { goodCountries++; Currency currency = Currency.getInstance(locale); @@ -180,14 +190,16 @@ public void localeMappingTest() { } } - // Check an invalid country code + // Check an invalid country code supplied via the region override @Test - public void invalidCountryTest() { + public void invalidCountryRegionOverrideTest() { + // Override US with nonsensical country + var loc = Locale.forLanguageTag("en-US-u-rg-XXzzzz"); Locale l = new Locale("", "EU"); IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, - ()-> Currency.getInstance(l), "Did not throw IAE"); - assertEquals("The country of the input locale is not a valid" + - " ISO 3166 country code", ex.getMessage()); + ()-> Currency.getInstance(loc), "Did not throw IAE"); + assertEquals("The country of the input locale: \"%s\" is not a valid ISO 3166 country code" + .formatted(loc), ex.getMessage()); } // Ensure a selection of countries have the expected currency