From 4e5e4af3e61c65fb1c602652ce8bfc211122d8de Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Sat, 20 Jun 2015 18:37:48 +0300 Subject: [PATCH] Add support for NumberFormat.get*Format methods --- .../classlib/impl/unicode/CLDRHelper.java | 15 ++-- .../classlib/impl/unicode/CLDRLocale.java | 15 ++++ .../classlib/impl/unicode/CLDRReader.java | 9 +++ .../DefaultLocaleMetadataGenerator.java | 2 +- .../NumberFormatMetadataGenerator.java | 72 +++++++++++++++++++ .../classlib/java/text/TDecimalFormat.java | 8 ++- .../classlib/java/text/TNumberFormat.java | 14 +++- .../classlib/java/text/NumberFormatTest.java | 44 ++++++++++++ 8 files changed, 169 insertions(+), 10 deletions(-) create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/impl/unicode/NumberFormatMetadataGenerator.java create mode 100644 teavm-tests/src/test/java/org/teavm/classlib/java/text/NumberFormatTest.java diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/impl/unicode/CLDRHelper.java b/teavm-classlib/src/main/java/org/teavm/classlib/impl/unicode/CLDRHelper.java index 8975def9d..524e9020d 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/impl/unicode/CLDRHelper.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/impl/unicode/CLDRHelper.java @@ -173,20 +173,23 @@ public class CLDRHelper { return resolveFormatSymbols(getNumberFormatMap(), language, country); } + @MetadataProvider(NumberFormatMetadataGenerator.class) private static native ResourceMap getNumberFormatMap(); - public static String resolveDecimalFormat(String language, String country) { - return resolveFormatSymbols(getDecimalFormatMap(), language, country); - } - - private static native ResourceMap getDecimalFormatMap(); - public static String resolvePercentFormat(String language, String country) { return resolveFormatSymbols(getPercentFormatMap(), language, country); } + @MetadataProvider(NumberFormatMetadataGenerator.class) private static native ResourceMap getPercentFormatMap(); + public static String resolveCurrencyFormat(String language, String country) { + return resolveFormatSymbols(getCurrencyFormatMap(), language, country); + } + + @MetadataProvider(NumberFormatMetadataGenerator.class) + private static native ResourceMap getCurrencyFormatMap(); + private static DateFormatCollection resolveDateFormats(ResourceMap map, String language, String country) { String localeCode = getCode(language, country); diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/impl/unicode/CLDRLocale.java b/teavm-classlib/src/main/java/org/teavm/classlib/impl/unicode/CLDRLocale.java index 44422dc46..6d9a003ad 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/impl/unicode/CLDRLocale.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/impl/unicode/CLDRLocale.java @@ -39,6 +39,9 @@ public class CLDRLocale { CLDRDateFormats dateTimeFormats; CLDRTimeZone[] timeZones; CLDRDecimalData decimalData = new CLDRDecimalData(); + String numberFormat; + String percentFormat; + String currencyFormat; public Map getLanguages() { return Collections.unmodifiableMap(languages); @@ -95,4 +98,16 @@ public class CLDRLocale { public CLDRDecimalData getDecimalData() { return decimalData; } + + public String getNumberFormat() { + return numberFormat; + } + + public String getPercentFormat() { + return percentFormat; + } + + public String getCurrencyFormat() { + return currencyFormat; + } } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/impl/unicode/CLDRReader.java b/teavm-classlib/src/main/java/org/teavm/classlib/impl/unicode/CLDRReader.java index c1ea2bccd..965c3cc22 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/impl/unicode/CLDRReader.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/impl/unicode/CLDRReader.java @@ -225,6 +225,15 @@ public class CLDRReader { locale.decimalData.perMille = symbolsJson.get("perMille").getAsString().charAt(0); locale.decimalData.infinity = symbolsJson.get("infinity").getAsString(); locale.decimalData.NaN = symbolsJson.get("nan").getAsString(); + + JsonObject numberJson = numbersJson.get("decimalFormats-numberSystem-" + numbering).getAsJsonObject(); + locale.numberFormat = numberJson.get("standard").getAsString(); + + JsonObject percentJson = numbersJson.get("percentFormats-numberSystem-" + numbering).getAsJsonObject(); + locale.percentFormat = percentJson.get("standard").getAsString(); + + JsonObject currencyJson = numbersJson.get("currencyFormats-numberSystem-" + numbering).getAsJsonObject(); + locale.currencyFormat = currencyJson.get("standard").getAsString(); } private void readEras(String localeCode, CLDRLocale locale, JsonObject root) { diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/impl/unicode/DefaultLocaleMetadataGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlib/impl/unicode/DefaultLocaleMetadataGenerator.java index 4bfb05ecd..41c8e837c 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/impl/unicode/DefaultLocaleMetadataGenerator.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/impl/unicode/DefaultLocaleMetadataGenerator.java @@ -29,7 +29,7 @@ public class DefaultLocaleMetadataGenerator implements MetadataGenerator { @Override public Resource generateMetadata(MetadataGeneratorContext context, MethodReference method) { StringResource result = context.createResource(StringResource.class); - result.setValue(context.getProperties().getProperty("java.util.Locale.default", "en_EN")); + result.setValue(context.getProperties().getProperty("java.util.Locale.default", "en_GB")); return result; } } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/impl/unicode/NumberFormatMetadataGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlib/impl/unicode/NumberFormatMetadataGenerator.java new file mode 100644 index 000000000..5c757bfc6 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/impl/unicode/NumberFormatMetadataGenerator.java @@ -0,0 +1,72 @@ +/* + * Copyright 2015 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.teavm.classlib.impl.unicode; + +import java.util.Map; +import org.teavm.model.MethodReference; +import org.teavm.platform.metadata.MetadataGenerator; +import org.teavm.platform.metadata.MetadataGeneratorContext; +import org.teavm.platform.metadata.Resource; +import org.teavm.platform.metadata.ResourceMap; +import org.teavm.platform.metadata.StringResource; + +/** + * + * @author Alexey Andreev + */ +public class NumberFormatMetadataGenerator implements MetadataGenerator { + @Override + public Resource generateMetadata(MetadataGeneratorContext context, MethodReference method) { + CLDRReader reader = context.getService(CLDRReader.class); + ResourceMap result = context.createResourceMap(); + FormatAccessor accessor; + switch (method.getName()) { + case "getNumberFormatMap": + accessor = new FormatAccessor() { + @Override public String getFormat(CLDRLocale locale) { + return locale.numberFormat; + } + }; + break; + case "getCurrencyFormatMap": + accessor = new FormatAccessor() { + @Override public String getFormat(CLDRLocale locale) { + return locale.currencyFormat; + } + }; + break; + case "getPercentFormatMap": + accessor = new FormatAccessor() { + @Override public String getFormat(CLDRLocale locale) { + return locale.percentFormat; + } + }; + break; + default: + throw new AssertionError(); + } + for (Map.Entry entry : reader.getKnownLocales().entrySet()) { + StringResource format = context.createResource(StringResource.class); + format.setValue(accessor.getFormat(entry.getValue())); + result.put(entry.getKey(), format); + } + return result; + } + + interface FormatAccessor { + String getFormat(CLDRLocale locale); + } +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/text/TDecimalFormat.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/TDecimalFormat.java index 9db41c46d..1f9e09f87 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/text/TDecimalFormat.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/TDecimalFormat.java @@ -51,7 +51,7 @@ public class TDecimalFormat extends TNumberFormat { int exponentDigits; public TDecimalFormat() { - this(CLDRHelper.resolveDecimalFormat(TLocale.getDefault().getLanguage(), TLocale.getDefault().getCountry())); + this(CLDRHelper.resolveNumberFormat(TLocale.getDefault().getLanguage(), TLocale.getDefault().getCountry())); } public TDecimalFormat(String pattern) { @@ -1227,7 +1227,11 @@ public class TDecimalFormat extends TNumberFormat { static class CurrencyField implements FormatField { @Override public void render(TDecimalFormat format, StringBuffer buffer) { - buffer.append(format.getCurrency().getSymbol(format.symbols.getLocale())); + if (format.getCurrency() == null) { + buffer.append('¤'); + } else { + buffer.append(format.getCurrency().getSymbol(format.symbols.getLocale())); + } } } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/text/TNumberFormat.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/TNumberFormat.java index 60ea007be..effadfc73 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/text/TNumberFormat.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/TNumberFormat.java @@ -106,6 +106,9 @@ public abstract class TNumberFormat extends TFormat { String pattern = CLDRHelper.resolveNumberFormat(locale.getLanguage(), locale.getCountry()); TDecimalFormat format = new TDecimalFormat(pattern, new TDecimalFormatSymbols(locale)); format.setParseIntegerOnly(true); + format.setMinimumFractionDigits(0); + format.setMaximumFractionDigits(0); + format.setDecimalSeparatorAlwaysShown(false); return format; } @@ -138,7 +141,7 @@ public abstract class TNumberFormat extends TFormat { } public static TNumberFormat getNumberInstance(TLocale locale) { - String pattern = CLDRHelper.resolveDecimalFormat(locale.getLanguage(), locale.getCountry()); + String pattern = CLDRHelper.resolveNumberFormat(locale.getLanguage(), locale.getCountry()); return new TDecimalFormat(pattern, new TDecimalFormatSymbols(locale)); } @@ -151,6 +154,15 @@ public abstract class TNumberFormat extends TFormat { return new TDecimalFormat(pattern, new TDecimalFormatSymbols(locale)); } + public final static TNumberFormat getCurrencyInstance() { + return getCurrencyInstance(TLocale.getDefault()); + } + + public final static TNumberFormat getCurrencyInstance(TLocale locale) { + String pattern = CLDRHelper.resolveCurrencyFormat(locale.getLanguage(), locale.getCountry()); + return new TDecimalFormat(pattern, new TDecimalFormatSymbols(locale)); + } + @Override public int hashCode() { return (groupingUsed ? 1231 : 1237) + (parseIntegerOnly ? 1231 : 1237) diff --git a/teavm-tests/src/test/java/org/teavm/classlib/java/text/NumberFormatTest.java b/teavm-tests/src/test/java/org/teavm/classlib/java/text/NumberFormatTest.java new file mode 100644 index 000000000..5c0a5d4fa --- /dev/null +++ b/teavm-tests/src/test/java/org/teavm/classlib/java/text/NumberFormatTest.java @@ -0,0 +1,44 @@ +package org.teavm.classlib.java.text; + +import static org.junit.Assert.*; +import java.text.NumberFormat; +import java.util.Currency; +import java.util.Locale; +import org.junit.Ignore; +import org.junit.Test; + +/** + * + * @author Alexey Andreev + */ +public class NumberFormatTest { + @Test + public void formatsNumber() { + NumberFormat format = NumberFormat.getNumberInstance(new Locale("en")); + assertEquals("123,456.789", format.format(123456.789123)); + + format = NumberFormat.getNumberInstance(new Locale("ru")); + assertEquals("123\u00A0456,789", format.format(123456.789123)); + } + + @Test + public void formatsCurrency() { + NumberFormat format = NumberFormat.getCurrencyInstance(new Locale("en", "US")); + format.setCurrency(Currency.getInstance("RUB")); + assertEquals("RUB123,456.79", format.format(123456.789123)); + + format = NumberFormat.getCurrencyInstance(new Locale("ru", "RU")); + format.setCurrency(Currency.getInstance("RUB")); + assertEquals("123 456,79 руб.", format.format(123456.789123).replace('\u00A0', ' ')); + } + + @Test + @Ignore + public void formatsPercent() { + NumberFormat format = NumberFormat.getPercentInstance(new Locale("en", "US")); + assertEquals("12,345,679%", format.format(123456.789123)); + + format = NumberFormat.getPercentInstance(new Locale("ru", "RU")); + assertEquals("12 345 679 %", format.format(123456.789123).replace('\u00A0', ' ')); + } +}