| /* |
| * Copyright (c) 2012, 2017, 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 |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| /* |
| * This file is available under and governed by the GNU General Public |
| * License version 2 only, as published by the Free Software Foundation. |
| * However, the following notice accompanied the original version of this |
| * file: |
| * |
| * Copyright (c) 2011-2012, Stephen Colebourne & Michael Nascimento Santos |
| * |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * |
| * * Redistributions of source code must retain the above copyright notice, |
| * this list of conditions and the following disclaimer. |
| * |
| * * Redistributions in binary form must reproduce the above copyright notice, |
| * this list of conditions and the following disclaimer in the documentation |
| * and/or other materials provided with the distribution. |
| * |
| * * Neither the name of JSR-310 nor the names of its contributors |
| * may be used to endorse or promote products derived from this software |
| * without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
| * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| package java.time.format; |
| |
| import android.icu.text.DateFormatSymbols; |
| import android.icu.util.ULocale; |
| |
| import static java.time.temporal.ChronoField.AMPM_OF_DAY; |
| import static java.time.temporal.ChronoField.DAY_OF_WEEK; |
| import static java.time.temporal.ChronoField.ERA; |
| import static java.time.temporal.ChronoField.MONTH_OF_YEAR; |
| |
| import com.android.icu.text.ExtendedDateFormatSymbols; |
| |
| import java.time.chrono.Chronology; |
| import java.time.chrono.IsoChronology; |
| import java.time.chrono.JapaneseChronology; |
| import java.time.temporal.ChronoField; |
| import java.time.temporal.IsoFields; |
| import java.time.temporal.TemporalField; |
| import java.util.AbstractMap.SimpleImmutableEntry; |
| import java.util.ArrayList; |
| import java.util.Calendar; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.concurrent.ConcurrentHashMap; |
| import java.util.concurrent.ConcurrentMap; |
| |
| import sun.util.locale.provider.CalendarDataUtility; |
| |
| /** |
| * A provider to obtain the textual form of a date-time field. |
| * |
| * @implSpec |
| * Implementations must be thread-safe. |
| * Implementations should cache the textual information. |
| * |
| * @since 1.8 |
| */ |
| class DateTimeTextProvider { |
| |
| /** Cache. */ |
| private static final ConcurrentMap<Entry<TemporalField, Locale>, Object> CACHE = new ConcurrentHashMap<>(16, 0.75f, 2); |
| /** Comparator. */ |
| private static final Comparator<Entry<String, Long>> COMPARATOR = new Comparator<Entry<String, Long>>() { |
| @Override |
| public int compare(Entry<String, Long> obj1, Entry<String, Long> obj2) { |
| return obj2.getKey().length() - obj1.getKey().length(); // longest to shortest |
| } |
| }; |
| |
| // Singleton instance |
| private static final DateTimeTextProvider INSTANCE = new DateTimeTextProvider(); |
| |
| DateTimeTextProvider() {} |
| |
| /** |
| * Gets the provider of text. |
| * |
| * @return the provider, not null |
| */ |
| static DateTimeTextProvider getInstance() { |
| return INSTANCE; |
| } |
| |
| /** |
| * Gets the text for the specified field, locale and style |
| * for the purpose of formatting. |
| * <p> |
| * The text associated with the value is returned. |
| * The null return value should be used if there is no applicable text, or |
| * if the text would be a numeric representation of the value. |
| * |
| * @param field the field to get text for, not null |
| * @param value the field value to get text for, not null |
| * @param style the style to get text for, not null |
| * @param locale the locale to get text for, not null |
| * @return the text for the field value, null if no text found |
| */ |
| public String getText(TemporalField field, long value, TextStyle style, Locale locale) { |
| Object store = findStore(field, locale); |
| if (store instanceof LocaleStore) { |
| return ((LocaleStore) store).getText(value, style); |
| } |
| return null; |
| } |
| |
| /** |
| * Gets the text for the specified chrono, field, locale and style |
| * for the purpose of formatting. |
| * <p> |
| * The text associated with the value is returned. |
| * The null return value should be used if there is no applicable text, or |
| * if the text would be a numeric representation of the value. |
| * |
| * @param chrono the Chronology to get text for, not null |
| * @param field the field to get text for, not null |
| * @param value the field value to get text for, not null |
| * @param style the style to get text for, not null |
| * @param locale the locale to get text for, not null |
| * @return the text for the field value, null if no text found |
| */ |
| public String getText(Chronology chrono, TemporalField field, long value, |
| TextStyle style, Locale locale) { |
| if (chrono == IsoChronology.INSTANCE |
| || !(field instanceof ChronoField)) { |
| return getText(field, value, style, locale); |
| } |
| |
| int fieldIndex; |
| int fieldValue; |
| if (field == ERA) { |
| fieldIndex = Calendar.ERA; |
| if (chrono == JapaneseChronology.INSTANCE) { |
| if (value == -999) { |
| fieldValue = 0; |
| } else { |
| fieldValue = (int) value + 2; |
| } |
| } else { |
| fieldValue = (int) value; |
| } |
| } else if (field == MONTH_OF_YEAR) { |
| fieldIndex = Calendar.MONTH; |
| fieldValue = (int) value - 1; |
| } else if (field == DAY_OF_WEEK) { |
| fieldIndex = Calendar.DAY_OF_WEEK; |
| fieldValue = (int) value + 1; |
| if (fieldValue > 7) { |
| fieldValue = Calendar.SUNDAY; |
| } |
| } else if (field == AMPM_OF_DAY) { |
| fieldIndex = Calendar.AM_PM; |
| fieldValue = (int) value; |
| } else { |
| return null; |
| } |
| return CalendarDataUtility.retrieveJavaTimeFieldValueName( |
| chrono.getCalendarType(), fieldIndex, fieldValue, style.toCalendarStyle(), locale); |
| } |
| |
| /** |
| * Gets an iterator of text to field for the specified field, locale and style |
| * for the purpose of parsing. |
| * <p> |
| * The iterator must be returned in order from the longest text to the shortest. |
| * <p> |
| * The null return value should be used if there is no applicable parsable text, or |
| * if the text would be a numeric representation of the value. |
| * Text can only be parsed if all the values for that field-style-locale combination are unique. |
| * |
| * @param field the field to get text for, not null |
| * @param style the style to get text for, null for all parsable text |
| * @param locale the locale to get text for, not null |
| * @return the iterator of text to field pairs, in order from longest text to shortest text, |
| * null if the field or style is not parsable |
| */ |
| public Iterator<Entry<String, Long>> getTextIterator(TemporalField field, TextStyle style, Locale locale) { |
| Object store = findStore(field, locale); |
| if (store instanceof LocaleStore) { |
| return ((LocaleStore) store).getTextIterator(style); |
| } |
| return null; |
| } |
| |
| /** |
| * Gets an iterator of text to field for the specified chrono, field, locale and style |
| * for the purpose of parsing. |
| * <p> |
| * The iterator must be returned in order from the longest text to the shortest. |
| * <p> |
| * The null return value should be used if there is no applicable parsable text, or |
| * if the text would be a numeric representation of the value. |
| * Text can only be parsed if all the values for that field-style-locale combination are unique. |
| * |
| * @param chrono the Chronology to get text for, not null |
| * @param field the field to get text for, not null |
| * @param style the style to get text for, null for all parsable text |
| * @param locale the locale to get text for, not null |
| * @return the iterator of text to field pairs, in order from longest text to shortest text, |
| * null if the field or style is not parsable |
| */ |
| public Iterator<Entry<String, Long>> getTextIterator(Chronology chrono, TemporalField field, |
| TextStyle style, Locale locale) { |
| if (chrono == IsoChronology.INSTANCE |
| || !(field instanceof ChronoField)) { |
| return getTextIterator(field, style, locale); |
| } |
| |
| int fieldIndex; |
| switch ((ChronoField)field) { |
| case ERA: |
| fieldIndex = Calendar.ERA; |
| break; |
| case MONTH_OF_YEAR: |
| fieldIndex = Calendar.MONTH; |
| break; |
| case DAY_OF_WEEK: |
| fieldIndex = Calendar.DAY_OF_WEEK; |
| break; |
| case AMPM_OF_DAY: |
| fieldIndex = Calendar.AM_PM; |
| break; |
| default: |
| return null; |
| } |
| |
| int calendarStyle = (style == null) ? Calendar.ALL_STYLES : style.toCalendarStyle(); |
| Map<String, Integer> map = CalendarDataUtility.retrieveJavaTimeFieldValueNames( |
| chrono.getCalendarType(), fieldIndex, calendarStyle, locale); |
| if (map == null) { |
| return null; |
| } |
| List<Entry<String, Long>> list = new ArrayList<>(map.size()); |
| switch (fieldIndex) { |
| case Calendar.ERA: |
| for (Map.Entry<String, Integer> entry : map.entrySet()) { |
| int era = entry.getValue(); |
| if (chrono == JapaneseChronology.INSTANCE) { |
| if (era == 0) { |
| era = -999; |
| } else { |
| era -= 2; |
| } |
| } |
| list.add(createEntry(entry.getKey(), (long)era)); |
| } |
| break; |
| case Calendar.MONTH: |
| for (Map.Entry<String, Integer> entry : map.entrySet()) { |
| list.add(createEntry(entry.getKey(), (long)(entry.getValue() + 1))); |
| } |
| break; |
| case Calendar.DAY_OF_WEEK: |
| for (Map.Entry<String, Integer> entry : map.entrySet()) { |
| list.add(createEntry(entry.getKey(), (long)toWeekDay(entry.getValue()))); |
| } |
| break; |
| default: |
| for (Map.Entry<String, Integer> entry : map.entrySet()) { |
| list.add(createEntry(entry.getKey(), (long)entry.getValue())); |
| } |
| break; |
| } |
| return list.iterator(); |
| } |
| |
| private Object findStore(TemporalField field, Locale locale) { |
| Entry<TemporalField, Locale> key = createEntry(field, locale); |
| Object store = CACHE.get(key); |
| if (store == null) { |
| store = createStore(field, locale); |
| CACHE.putIfAbsent(key, store); |
| store = CACHE.get(key); |
| } |
| return store; |
| } |
| |
| private static int toWeekDay(int calWeekDay) { |
| if (calWeekDay == Calendar.SUNDAY) { |
| return 7; |
| } else { |
| return calWeekDay - 1; |
| } |
| } |
| |
| private Object createStore(TemporalField field, Locale locale) { |
| Map<TextStyle, Map<Long, String>> styleMap = new HashMap<>(); |
| if (field == ERA) { |
| for (TextStyle textStyle : TextStyle.values()) { |
| if (textStyle.isStandalone()) { |
| // Stand-alone isn't applicable to era names. |
| continue; |
| } |
| Map<String, Integer> displayNames = CalendarDataUtility.retrieveJavaTimeFieldValueNames( |
| "gregory", Calendar.ERA, textStyle.toCalendarStyle(), locale); |
| if (displayNames != null) { |
| Map<Long, String> map = new HashMap<>(); |
| for (Entry<String, Integer> entry : displayNames.entrySet()) { |
| map.put((long) entry.getValue(), entry.getKey()); |
| } |
| if (!map.isEmpty()) { |
| styleMap.put(textStyle, map); |
| } |
| } |
| } |
| return new LocaleStore(styleMap); |
| } |
| |
| if (field == MONTH_OF_YEAR) { |
| for (TextStyle textStyle : TextStyle.values()) { |
| Map<Long, String> map = new HashMap<>(); |
| // Narrow names may have duplicated names, such as "J" for January, June, July. |
| // Get names one by one in that case. |
| if ((textStyle.equals(TextStyle.NARROW) || |
| textStyle.equals(TextStyle.NARROW_STANDALONE))) { |
| for (int month = Calendar.JANUARY; month <= Calendar.DECEMBER; month++) { |
| String name; |
| name = CalendarDataUtility.retrieveJavaTimeFieldValueName( |
| "gregory", Calendar.MONTH, |
| month, textStyle.toCalendarStyle(), locale); |
| if (name == null) { |
| break; |
| } |
| map.put((month + 1L), name); |
| } |
| } else { |
| Map<String, Integer> displayNames = CalendarDataUtility.retrieveJavaTimeFieldValueNames( |
| "gregory", Calendar.MONTH, textStyle.toCalendarStyle(), locale); |
| if (displayNames != null) { |
| for (Entry<String, Integer> entry : displayNames.entrySet()) { |
| map.put((long)(entry.getValue() + 1), entry.getKey()); |
| } |
| } else { |
| // Although probability is very less, but if other styles have duplicate names. |
| // Get names one by one in that case. |
| for (int month = Calendar.JANUARY; month <= Calendar.DECEMBER; month++) { |
| String name; |
| name = CalendarDataUtility.retrieveJavaTimeFieldValueName( |
| "gregory", Calendar.MONTH, month, textStyle.toCalendarStyle(), locale); |
| if (name == null) { |
| break; |
| } |
| map.put((month + 1L), name); |
| } |
| } |
| } |
| if (!map.isEmpty()) { |
| styleMap.put(textStyle, map); |
| } |
| } |
| return new LocaleStore(styleMap); |
| } |
| |
| if (field == DAY_OF_WEEK) { |
| for (TextStyle textStyle : TextStyle.values()) { |
| Map<Long, String> map = new HashMap<>(); |
| // Narrow names may have duplicated names, such as "S" for Sunday and Saturday. |
| // Get names one by one in that case. |
| if ((textStyle.equals(TextStyle.NARROW) || |
| textStyle.equals(TextStyle.NARROW_STANDALONE))) { |
| for (int wday = Calendar.SUNDAY; wday <= Calendar.SATURDAY; wday++) { |
| String name; |
| name = CalendarDataUtility.retrieveJavaTimeFieldValueName( |
| "gregory", Calendar.DAY_OF_WEEK, |
| wday, textStyle.toCalendarStyle(), locale); |
| if (name == null) { |
| break; |
| } |
| map.put((long)toWeekDay(wday), name); |
| } |
| } else { |
| Map<String, Integer> displayNames = CalendarDataUtility.retrieveJavaTimeFieldValueNames( |
| "gregory", Calendar.DAY_OF_WEEK, textStyle.toCalendarStyle(), locale); |
| if (displayNames != null) { |
| for (Entry<String, Integer> entry : displayNames.entrySet()) { |
| map.put((long)toWeekDay(entry.getValue()), entry.getKey()); |
| } |
| } else { |
| // Although probability is very less, but if other styles have duplicate names. |
| // Get names one by one in that case. |
| for (int wday = Calendar.SUNDAY; wday <= Calendar.SATURDAY; wday++) { |
| String name; |
| name = CalendarDataUtility.retrieveJavaTimeFieldValueName( |
| "gregory", Calendar.DAY_OF_WEEK, wday, textStyle.toCalendarStyle(), locale); |
| if (name == null) { |
| break; |
| } |
| map.put((long)toWeekDay(wday), name); |
| } |
| } |
| } |
| if (!map.isEmpty()) { |
| styleMap.put(textStyle, map); |
| } |
| } |
| return new LocaleStore(styleMap); |
| } |
| |
| if (field == AMPM_OF_DAY) { |
| for (TextStyle textStyle : TextStyle.values()) { |
| if (textStyle.isStandalone()) { |
| // Stand-alone isn't applicable to AM/PM. |
| continue; |
| } |
| Map<String, Integer> displayNames = CalendarDataUtility.retrieveJavaTimeFieldValueNames( |
| "gregory", Calendar.AM_PM, textStyle.toCalendarStyle(), locale); |
| if (displayNames != null) { |
| Map<Long, String> map = new HashMap<>(); |
| for (Entry<String, Integer> entry : displayNames.entrySet()) { |
| map.put((long) entry.getValue(), entry.getKey()); |
| } |
| if (!map.isEmpty()) { |
| styleMap.put(textStyle, map); |
| } |
| } |
| } |
| return new LocaleStore(styleMap); |
| } |
| |
| if (field == IsoFields.QUARTER_OF_YEAR) { |
| // BEGIN Android-changed: Use ICU resources. |
| /* |
| // The order of keys must correspond to the TextStyle.values() order. |
| final String[] keys = { |
| "QuarterNames", |
| "standalone.QuarterNames", |
| "QuarterAbbreviations", |
| "standalone.QuarterAbbreviations", |
| "QuarterNarrows", |
| "standalone.QuarterNarrows", |
| }; |
| for (int i = 0; i < keys.length; i++) { |
| String[] names = getLocalizedResource(keys[i], locale); |
| if (names != null) { |
| Map<Long, String> map = new HashMap<>(); |
| for (int q = 0; q < names.length; q++) { |
| map.put((long) (q + 1), names[q]); |
| } |
| styleMap.put(TextStyle.values()[i], map); |
| } |
| } |
| */ |
| ULocale uLocale = ULocale.forLocale(locale); |
| // TODO: Figure why we forced Gregorian calendar in the first patch in |
| // https://r.android.com/311224 |
| uLocale.setKeywordValue("calendar", "gregorian"); |
| ExtendedDateFormatSymbols extendedDfs = ExtendedDateFormatSymbols.getInstance(uLocale); |
| DateFormatSymbols dfs = extendedDfs.getDateFormatSymbols(); |
| styleMap.put(TextStyle.FULL, extractQuarters( |
| dfs.getQuarters(DateFormatSymbols.FORMAT, DateFormatSymbols.WIDE))); |
| styleMap.put(TextStyle.FULL_STANDALONE, extractQuarters( |
| dfs.getQuarters(DateFormatSymbols.STANDALONE, DateFormatSymbols.WIDE))); |
| styleMap.put(TextStyle.SHORT, extractQuarters( |
| dfs.getQuarters(DateFormatSymbols.FORMAT, DateFormatSymbols.ABBREVIATED))); |
| styleMap.put(TextStyle.SHORT_STANDALONE, extractQuarters( |
| dfs.getQuarters(DateFormatSymbols.STANDALONE, DateFormatSymbols.ABBREVIATED))); |
| styleMap.put(TextStyle.NARROW, extractQuarters( |
| extendedDfs.getNarrowQuarters(DateFormatSymbols.FORMAT))); |
| styleMap.put(TextStyle.NARROW_STANDALONE, extractQuarters( |
| extendedDfs.getNarrowQuarters(DateFormatSymbols.STANDALONE))); |
| |
| // END Android-changed: Use ICU resources. |
| return new LocaleStore(styleMap); |
| } |
| |
| return ""; // null marker for map |
| } |
| |
| // BEGIN Android-added: Extracts a Map of quarter names. |
| private static Map<Long, String> extractQuarters(String[] quarters) { |
| Map<Long, String> map = new HashMap<>(); |
| for (int q = 0; q < quarters.length; q++) { |
| map.put((long) (q + 1), quarters[q]); |
| } |
| return map; |
| } |
| // END Android-added: Extracts a Map of quarter names. |
| |
| /** |
| * Helper method to create an immutable entry. |
| * |
| * @param text the text, not null |
| * @param field the field, not null |
| * @return the entry, not null |
| */ |
| private static <A, B> Entry<A, B> createEntry(A text, B field) { |
| return new SimpleImmutableEntry<>(text, field); |
| } |
| |
| // BEGIN Android-removed: Android uses ICU resources and has no LocaleProviderAdapter. |
| /** |
| * Returns the localized resource of the given key and locale, or null |
| * if no localized resource is available. |
| * |
| * @param key the key of the localized resource, not null |
| * @param locale the locale, not null |
| * @return the localized resource, or null if not available |
| * @throws NullPointerException if key or locale is null |
| */ |
| // @SuppressWarnings("unchecked") |
| // static <T> T getLocalizedResource(String key, Locale locale) { |
| // LocaleResources lr = LocaleProviderAdapter.getResourceBundleBased() |
| // .getLocaleResources( |
| // CalendarDataUtility.findRegionOverride(locale)); |
| // ResourceBundle rb = lr.getJavaTimeFormatData(); |
| // return rb.containsKey(key) ? (T) rb.getObject(key) : null; |
| // } |
| // END Android-removed: Android uses ICU resources and has no LocaleProviderAdapter. |
| |
| /** |
| * Stores the text for a single locale. |
| * <p> |
| * Some fields have a textual representation, such as day-of-week or month-of-year. |
| * These textual representations can be captured in this class for printing |
| * and parsing. |
| * <p> |
| * This class is immutable and thread-safe. |
| */ |
| static final class LocaleStore { |
| /** |
| * Map of value to text. |
| */ |
| private final Map<TextStyle, Map<Long, String>> valueTextMap; |
| /** |
| * Parsable data. |
| */ |
| private final Map<TextStyle, List<Entry<String, Long>>> parsable; |
| |
| /** |
| * Constructor. |
| * |
| * @param valueTextMap the map of values to text to store, assigned and not altered, not null |
| */ |
| LocaleStore(Map<TextStyle, Map<Long, String>> valueTextMap) { |
| this.valueTextMap = valueTextMap; |
| Map<TextStyle, List<Entry<String, Long>>> map = new HashMap<>(); |
| List<Entry<String, Long>> allList = new ArrayList<>(); |
| for (Map.Entry<TextStyle, Map<Long, String>> vtmEntry : valueTextMap.entrySet()) { |
| Map<String, Entry<String, Long>> reverse = new HashMap<>(); |
| for (Map.Entry<Long, String> entry : vtmEntry.getValue().entrySet()) { |
| if (reverse.put(entry.getValue(), createEntry(entry.getValue(), entry.getKey())) != null) { |
| // TODO: BUG: this has no effect |
| continue; // not parsable, try next style |
| } |
| } |
| List<Entry<String, Long>> list = new ArrayList<>(reverse.values()); |
| Collections.sort(list, COMPARATOR); |
| map.put(vtmEntry.getKey(), list); |
| allList.addAll(list); |
| map.put(null, allList); |
| } |
| Collections.sort(allList, COMPARATOR); |
| this.parsable = map; |
| } |
| |
| /** |
| * Gets the text for the specified field value, locale and style |
| * for the purpose of printing. |
| * |
| * @param value the value to get text for, not null |
| * @param style the style to get text for, not null |
| * @return the text for the field value, null if no text found |
| */ |
| String getText(long value, TextStyle style) { |
| Map<Long, String> map = valueTextMap.get(style); |
| return map != null ? map.get(value) : null; |
| } |
| |
| /** |
| * Gets an iterator of text to field for the specified style for the purpose of parsing. |
| * <p> |
| * The iterator must be returned in order from the longest text to the shortest. |
| * |
| * @param style the style to get text for, null for all parsable text |
| * @return the iterator of text to field pairs, in order from longest text to shortest text, |
| * null if the style is not parsable |
| */ |
| Iterator<Entry<String, Long>> getTextIterator(TextStyle style) { |
| List<Entry<String, Long>> list = parsable.get(style); |
| return list != null ? list.iterator() : null; |
| } |
| } |
| } |