[NEW BUG] NumberFormat.parse fails in some scenarios

Roger Riggs Roger.Riggs at oracle.com
Wed Aug 26 14:56:13 UTC 2020


Hi Christoph,

Its worth investigating, tracking the issue with:

https://bugs.openjdk.java.net/browse/JDK-8252383

Bugs can be reported with:
    https://bugreport.java.com/bugreport/

Thanks, Roger


On 8/26/20 10:18 AM, Christoph Dreis wrote:
> Hi,
>
> A colleague of mine (filipe.silvestrim at innogames.com) approached me today that his code wasn’t working that converted a currency String into cents.
> Apparently, the code worked with Java 8 while it didn’t with 11+.
>
> public class Main {
>
> 	public static void main(String[] args) throws IOException {
> 		// System.setProperty("java.locale.providers", "JRE");
> 		System.out.println(getPriceInCents(Locale.GERMANY, "9,99 €"));
> 	}
>
> 	static int getPriceInCents(Locale locale, String price) {
> 		try {
> 			DecimalFormat format = (DecimalFormat) NumberFormat.getCurrencyInstance(locale);
> 			Number number = format.parse(price);
> 			return (int) (number.doubleValue() * 100);
> 		} catch (ParseException e) {
>                                             // This should be thrown on JDK 9+
> 			System.out.println(e);
> 		}
> 		return 0;
> 	}
>
> }
> 	
> After some digging I think this is caused by the changes done for JDK-8008577[1].
> When I change the java.locale.providers property to "JRE" for example, it works again.
>
> My investigations so far revealed that apparently the CLDR number pattern for the currency slightly differs.
>
> I created breakpoints in sun.util.locale.provider.NumberFormatProviderImpl::getInstance() to display some things:
>
>          LocaleProviderAdapter adapter = LocaleProviderAdapter.forType(type);
>          String[] numberPatterns = adapter.getLocaleResources(override).getNumberPatterns();
>          DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(override);
>          int entry = (choice == INTEGERSTYLE) ? NUMBERSTYLE : choice;
>          DecimalFormat format = new DecimalFormat(numberPatterns[entry], symbols);
>
> 	// CLDR (type)
> 	// #,##0.00 ¤ (numberPatterns[entry])
> 	// [35,44,35,35,48,46,48,48,-62,-96,-62,-92] (numberPatterns[entry] in bytes)
>
> 	//
> 	// JRE type
> 	// #,##0.00 ¤;-#,##0.00 ¤ (numberPatterns[entry])
> 	// [35,44,35,35,48,46,48,48,32,-62,-92,59,45,35,44,35,35,48,46,48,48,32,-62,-92] (numberPatterns[entry] in bytes)
>
> The JRE one includes the negative pattern, but the more interesting bit is that apparently the spacing differs here.
> For JRE it seems to be a normal space (the 32), but for CLDR it's showing [-62, -96] which seems to be a non breaking space aka nbsp.
>
> Ultimately this leads to a check failing in DecimalFormat when parsing the string "9,99 €" that obviously includes a normal space.
>
>              if (gotPositive) {
>                  // the regionMatches will return false because nbsp != space
>                  gotPositive = text.regionMatches(position,positiveSuffix,0,
>                                                   positiveSuffix.length());
>              }
>
> Which itself leads to the following in our case:
>
>          // fail if neither or both
>          if (gotPositive == gotNegative) {
>              parsePosition.errorIndex = position;
>              // We hit this part here which causes the parsing to fail
>              return false;
>          }
>
>
> There are workarounds - e.g. by setting java.locale.providers as already mentioned or setting format.setPositiveSuffix(" €"); to fix this particular case.
>
> Is this a bug or a feature or are we missing something?
>
> In case this is an actual bug we would appreciate a "reported-by" mentioning in an eventual fix.
>
> Thanks in advance. I do hope you can follow my thoughts in this email.
>
> [1] https://bugs.openjdk.java.net/browse/JDK-8008577
>
> Cheers,
> Christoph
>
>



More information about the core-libs-dev mailing list