Skip to content

Commit

Permalink
Support user-assigned country codes. (See issue TakahikoKawasaki#25.)
Browse files Browse the repository at this point in the history
  • Loading branch information
Derek Mahar committed Aug 17, 2017
1 parent a311dca commit 83722f4
Show file tree
Hide file tree
Showing 6 changed files with 240 additions and 32 deletions.
86 changes: 60 additions & 26 deletions src/main/java/com/neovisionaries/i18n/CountryCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@
*
* @author Takahiko Kawasaki
*/
public enum CountryCode
public enum CountryCode implements CountryCodeInterface
{

/**
Expand Down Expand Up @@ -2223,16 +2223,21 @@ public enum Assignment
NOT_USED
}


private static final Map<String, CountryCode> alpha3Map = new HashMap<String, CountryCode>();
private static final Map<String, CountryCode> alpha4Map = new HashMap<String, CountryCode>();
private static final Map<Integer, CountryCode> numericMap = new HashMap<Integer, CountryCode>();

private static final Map<String, CountryCodeInterface> alpha2Map = new HashMap<String, CountryCodeInterface>();
private static final Map<String, CountryCodeInterface> alpha3Map = new HashMap<String, CountryCodeInterface>();
private static final Map<String, CountryCodeInterface> alpha4Map = new HashMap<String, CountryCodeInterface>();
private static final Map<Integer, CountryCodeInterface> numericMap = new HashMap<Integer, CountryCodeInterface>();
private static final List<CountryCodeInterface> standardAndUserAssignedCodes = new ArrayList<CountryCodeInterface>();

static
{
for (CountryCode cc : values())
{
if (cc.getAlpha2() != null)
{
alpha2Map.put(cc.getAlpha2(), cc);
}

if (cc.getAlpha3() != null)
{
alpha3Map.put(cc.getAlpha3(), cc);
Expand All @@ -2242,6 +2247,8 @@ public enum Assignment
{
numericMap.put(Integer.valueOf(cc.getNumeric()), cc);
}

standardAndUserAssignedCodes.add(cc);
}

// FI and SF have the same alpha-3 code "FIN". FI should be used.
Expand Down Expand Up @@ -2293,6 +2300,8 @@ private CountryCode(String name, String alpha3, int numeric, Assignment assignme
*
* @return
* The country name.
*
* @see com.neovisionaries.i18n.CountryCodeInterface#getName()
*/
public String getName()
{
Expand All @@ -2309,6 +2318,8 @@ public String getName()
* >ISO 3166-1 alpha-2</a> code.
* {@link CountryCode#UNDEFINED} returns {@code "UNDEFINED"}
* which is not an official ISO 3166-1 alpha-2 code.
*
* @see com.neovisionaries.i18n.CountryCodeInterface#getAlpha2()
*/
public String getAlpha2()
{
Expand All @@ -2326,6 +2337,8 @@ public String getAlpha2()
* Some country codes reserved exceptionally (such as {@link #EU})
* returns {@code null}.
* {@link CountryCode#UNDEFINED} returns {@code null}, too.
*
* @see com.neovisionaries.i18n.CountryCodeInterface#getAlpha3()
*/
public String getAlpha3()
{
Expand All @@ -2343,6 +2356,8 @@ public String getAlpha3()
* Country codes reserved exceptionally (such as {@link #EU})
* returns {@code -1}.
* {@link CountryCode#UNDEFINED} returns {@code -1}, too.
*
* @see com.neovisionaries.i18n.CountryCodeInterface#getNumeric()
*/
public int getNumeric()
{
Expand All @@ -2358,6 +2373,8 @@ public int getNumeric()
*
* @see <a href="http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Decoding_table"
* >Decoding table of ISO 3166-1 alpha-2 codes</a>
*
* @see com.neovisionaries.i18n.CountryCodeInterface#getAssignment()
*/
public Assignment getAssignment()
{
Expand Down Expand Up @@ -2440,6 +2457,8 @@ public Assignment getAssignment()
*
* @return
* A {@code Locale} instance that matches this {@code CountryCode}.
*
* @see com.neovisionaries.i18n.CountryCodeInterface#toLocale()
*/
public Locale toLocale()
{
Expand Down Expand Up @@ -2479,6 +2498,8 @@ public Locale toLocale()
* @since 1.4
*
* @see Currency#getInstance(Locale)
*
* @see com.neovisionaries.i18n.CountryCodeInterface#getCurrency()
*/
public Currency getCurrency()
{
Expand Down Expand Up @@ -2521,7 +2542,7 @@ public Currency getCurrency()
*
* @see #getByCode(String, boolean)
*/
public static CountryCode getByCode(String code)
public static CountryCodeInterface getByCode(String code)
{
return getByCode(code, true);
}
Expand Down Expand Up @@ -2551,7 +2572,7 @@ public static CountryCode getByCode(String code)
*
* @see #getByCode(String, boolean)
*/
public static CountryCode getByCodeIgnoreCase(String code)
public static CountryCodeInterface getByCodeIgnoreCase(String code)
{
return getByCode(code, false);
}
Expand Down Expand Up @@ -2582,7 +2603,7 @@ public static CountryCode getByCodeIgnoreCase(String code)
* @return
* A {@code CountryCode} instance, or {@code null} if not found.
*/
public static CountryCode getByCode(String code, boolean caseSensitive)
public static CountryCodeInterface getByCode(String code, boolean caseSensitive)
{
if (code == null)
{
Expand Down Expand Up @@ -2633,7 +2654,7 @@ public static CountryCode getByCode(String code, boolean caseSensitive)
*
* @see Locale#getCountry()
*/
public static CountryCode getByLocale(Locale locale)
public static CountryCodeInterface getByLocale(Locale locale)
{
if (locale == null)
{
Expand Down Expand Up @@ -2686,26 +2707,19 @@ static String canonicalize(String code, boolean caseSensitive)
}


private static CountryCode getByAlpha2Code(String code)
private static CountryCodeInterface getByAlpha2Code(String code)
{
try
{
return Enum.valueOf(CountryCode.class, code);
}
catch (IllegalArgumentException e)
{
return null;
}
return alpha2Map.get(code);
}


private static CountryCode getByAlpha3Code(String code)
private static CountryCodeInterface getByAlpha3Code(String code)
{
return alpha3Map.get(code);
}


private static CountryCode getByAlpha4Code(String code)
private static CountryCodeInterface getByAlpha4Code(String code)
{
return alpha4Map.get(code);
}
Expand Down Expand Up @@ -2772,7 +2786,7 @@ private static CountryCode getByAlpha4Code(String code)
* A {@code CountryCode} instance, or {@code null} if not found.
* If 0 or a negative value is given, {@code null} is returned.
*/
public static CountryCode getByCode(int code)
public static CountryCodeInterface getByCode(int code)
{
if (code <= 0)
{
Expand Down Expand Up @@ -2806,7 +2820,7 @@ public static CountryCode getByCode(int code)
*
* @since 1.11
*/
public static List<CountryCode> findByName(String regex)
public static List<CountryCodeInterface> findByName(String regex)
{
if (regex == null)
{
Expand Down Expand Up @@ -2857,16 +2871,16 @@ public static List<CountryCode> findByName(String regex)
*
* @since 1.11
*/
public static List<CountryCode> findByName(Pattern pattern)
public static List<CountryCodeInterface> findByName(Pattern pattern)
{
if (pattern == null)
{
throw new IllegalArgumentException("pattern is null.");
}

List<CountryCode> list = new ArrayList<CountryCode>();
List<CountryCodeInterface> list = new ArrayList<CountryCodeInterface>();

for (CountryCode entry : values())
for (CountryCodeInterface entry : standardAndUserAssignedCodes)
{
// If the name matches the given pattern.
if (pattern.matcher(entry.getName()).matches())
Expand All @@ -2877,4 +2891,24 @@ public static List<CountryCode> findByName(Pattern pattern)

return list;
}

public static void addUserAssigned(CountryCodeInterface code)
{
standardAndUserAssignedCodes.add(code);

if (!alpha3Map.containsKey(code.getAlpha3()))
{
alpha3Map.put(code.getAlpha3(), code);
}

if (!alpha2Map.containsKey(code.getAlpha2()))
{
alpha2Map.put(code.getAlpha2(), code);
}

if (!numericMap.containsKey(code.getNumeric()))
{
numericMap.put(code.getNumeric(), code);
}
}
}
102 changes: 102 additions & 0 deletions src/main/java/com/neovisionaries/i18n/CountryCodeInterface.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package com.neovisionaries.i18n;

import java.util.Currency;
import java.util.Locale;

import com.neovisionaries.i18n.CountryCode.Assignment;

public interface CountryCodeInterface {

/**
* Get the country name.
*
* @return The country name.
*/
String getName();

/**
* Get the <a href="http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2"
* >ISO 3166-1 alpha-2</a> code.
*
* @return The standard <a href="http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2"
* >ISO 3166-1 alpha-2</a> code or one which is
* <a href="https://en.wikipedia.org/wiki/ISO_3166-1#Reserved_and_user-assigned_code_elements">reserved
* or user-assigned</a>. {@link CountryCode#UNDEFINED} returns
* {@code "UNDEFINED"} which is not an official ISO 3166-1 alpha-2 code.
*/
String getAlpha2();

/**
* Get the <a href="http://en.wikipedia.org/wiki/ISO_3166-1_alpha-3"
* >ISO 3166-1 alpha-3</a> code.
*
* @return The standard <a href="http://en.wikipedia.org/wiki/ISO_3166-1_alpha-3"
* >ISO 3166-1 alpha-3</a> code or one which is
* <a href="https://en.wikipedia.org/wiki/ISO_3166-1#Reserved_and_user-assigned_code_elements">reserved
* or user-assigned</a>. Some country codes reserved exceptionally (such as
* {@link #EU}) returns {@code null}. {@link CountryCode#UNDEFINED} returns
* {@code null}, too.
*/
String getAlpha3();

/**
* Get the <a href="http://en.wikipedia.org/wiki/ISO_3166-1_numeric"
* >ISO 3166-1 numeric</a> code.
*
* @return The standard <a href="http://en.wikipedia.org/wiki/ISO_3166-1_numeric"
* >ISO 3166-1 numeric</a> code or one which is
* <a href="https://en.wikipedia.org/wiki/ISO_3166-1#Reserved_and_user-assigned_code_elements">reserved
* or user-assigned</a>. Country codes reserved exceptionally (such as
* {@link #EU}) returns {@code -1}. {@link CountryCode#UNDEFINED} returns
* {@code -1}, too.
*/
int getNumeric();

/**
* Get the assignment state of this country code in ISO 3166-1.
*
* @return The assignment state.
*
* @see <a href="http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Decoding_table"
* >Decoding table of ISO 3166-1 alpha-2 codes</a>
*/
Assignment getAssignment();

/**
* Convert this {@code CountryCode} instance to a {@link Locale} instance.
*
* @return A {@code Locale} instance that matches this {@code CountryCode}.
*/
Locale toLocale();

/**
* Get the currency.
*
* <p>
* This method is an alias of {@link Currency}{@code .}{@link
* Currency#getInstance(Locale) getInstance}{@code (}{@link
* #toLocale()}{@code )}. The only difference is that this method returns
* {@code null} when {@code Currency.getInstance(Locale)} throws
* {@code IllegalArgumentException}.
* </p>
*
* <p>
* This method returns {@code null} when the territory represented by this
* {@code CountryCode} instance does not have a currency. {@link #AQ}
* (Antarctica) is one example.
* </p>
*
* <p>
* In addition, this method returns {@code null} also when the ISO 3166 code
* represented by this {@code CountryCode} instance is not supported by the
* implementation of {@link
* Currency#getInstance(Locale)}. At the time of this writing, {@link #SS}
* (South Sudan) is one example.
* </p>
*
* @return A {@code Currency} instance. In some cases, null is returned.
*
* @see Currency#getInstance(Locale)
*/
Currency getCurrency();
}
4 changes: 2 additions & 2 deletions src/main/java/com/neovisionaries/i18n/CurrencyCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -2635,7 +2635,7 @@ public static List<CurrencyCode> getByCountry(String country, boolean caseSensit
* {@code CurrencyCode} instance whose country list contains
* the specified country, the size of the returned list is zero.
*/
public static List<CurrencyCode> getByCountry(CountryCode country)
public static List<CurrencyCode> getByCountry(CountryCodeInterface country)
{
List<CurrencyCode> list = new ArrayList<CurrencyCode>();

Expand All @@ -2646,7 +2646,7 @@ public static List<CurrencyCode> getByCountry(CountryCode country)

for (CurrencyCode currency : values())
{
for (CountryCode cc : currency.countryList)
for (CountryCodeInterface cc : currency.countryList)
{
if (cc == country)
{
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/neovisionaries/i18n/LocaleCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -1027,7 +1027,7 @@ public LanguageCode getLanguage()
* The country code. This method may return null.
* For example, {@link #en LocaleCode.en}.getCountry() returns null.
*/
public CountryCode getCountry()
public CountryCodeInterface getCountry()
{
return country;
}
Expand Down Expand Up @@ -1678,7 +1678,7 @@ public static List<LocaleCode> getByCountry(String country, boolean caseSensitiv
*
* @since 1.3
*/
public static List<LocaleCode> getByCountry(CountryCode country)
public static List<LocaleCode> getByCountry(CountryCodeInterface country)
{
List<LocaleCode> list = new ArrayList<LocaleCode>();

Expand Down
Loading

0 comments on commit 83722f4

Please sign in to comment.