未加载特定于应用程序的语言环境变体的DateFormatProvider实现

时间:2013-04-22 14:42:46

标签: java

我有一个使用适当的java.text.spi.DateFormatProvider文件打包在jar中的DateFormatProvider实现,但是不会使用DateFormatProvider(实际上LocaleServiceProviderPool.getPool(DateFormatProvider.class).hasEntries()在下面的测试程序中为false。

DateFormatProvider的实现:

package dateformatproviders;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.text.spi.DateFormatProvider;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Locale;

public class DateFormatProviderImpl extends DateFormatProvider
{
  private static final CompareLocales COMPARE_LOCALES = new CompareLocales();
  private Locale[] availableLocales;
  private static final String VARIANT = "variant_xxx";
  private final String formatString;
  private final Object availableLocalesLock = new Object();

  /**
   * for each available locale create a variant using the given variantString.
   * Return the list of all these locales
   *
   * @param variantString must not be null
   * @return never null nor empty
   */
  public static Locale[] installVariant(String variantString)
  {
    Locale[] availableLocales = Locale.getAvailableLocales();
    Locale[] result = new Locale[availableLocales.length];
    int pos = 0;
    for (Locale locale : availableLocales)
    {
      Locale newLocale = createLocale(locale, variantString);
      result[pos] = newLocale;
      ++pos;
    }
    return result;
  }

  public static Locale createLocale(Locale originalDefaultLocale, String variant)
  {
    Locale modifiedDefaultLocale = new Locale(originalDefaultLocale.getLanguage(), originalDefaultLocale.getCountry(), variant);
    return modifiedDefaultLocale;
  }

  public DateFormatProviderImpl()
  {
    formatString = "HH:mm:ss 't' MM/dd/yy";
  }

  private DateFormat createDateFormat()
  {
    return new SimpleDateFormat(formatString);
  }

  @Override
  public final DateFormat getTimeInstance(int style, Locale locale)
  {
    checkArguments(locale, style);
    return createDateFormat();
  }

  @Override
  public final DateFormat getDateInstance(int style, Locale locale)
  {
    checkArguments(locale, style);
    return createDateFormat();
  }

  @Override
  public final DateFormat getDateTimeInstance(int dateStyle, int timeStyle, Locale locale)
  {
    checkArguments(locale, dateStyle, timeStyle);
    return createDateFormat();
  }

  @Override
  public final Locale[] getAvailableLocales()
  {
    synchronized (availableLocalesLock)
    {
      if (null == availableLocales)
      {
        Locale[] sourceLocales = installVariant(VARIANT);
        availableLocales = Arrays.copyOf(sourceLocales, sourceLocales.length);
        Arrays.sort(availableLocales, COMPARE_LOCALES);
      }
    }
    return availableLocales;
  }

  public final String getVariant()
  {
    return VARIANT;
  }

  private void checkArguments(Locale locale, int... styles)
  {
    for (int style : styles)
    {
      switch (style)
      {
        case DateFormat.SHORT:
        case DateFormat.MEDIUM:

        case DateFormat.LONG:
        case DateFormat.FULL:
          break;
        default:
          throw new IllegalArgumentException("style:" + style + " must be one of{" + DateFormat.SHORT + ',' + DateFormat.MEDIUM + ','
                  + DateFormat.LONG + ',' + DateFormat.FULL + '}');
      }
    }
    checkLocale(locale);
  }

  private void checkLocale(Locale locale)
  {
    if (null == locale)
    {
      throw new IllegalArgumentException("locale must not be null");
    }
    if (Arrays.binarySearch(availableLocales, locale, COMPARE_LOCALES) < 0)
    {
      throw new IllegalArgumentException("locale not supported:" + locale);
    }
  }

  private static class CompareLocales implements Comparator<Locale>
  {
    @Override
    public int compare(Locale lhs, Locale rhs)
    {
      if (null == lhs)
      {
        if (null == rhs)
        {
          return 0;
        }
        return -1;
      }
      if (null == rhs)
      {
        return 1;
      }
      String lhsLang = lhs.getLanguage();
      String rhsLang = rhs.getLanguage();
      int langCompare = lhsLang.compareTo(rhsLang);
      if (0 == langCompare)
      {
        String lhsCountry = lhs.getCountry();
        String rhsCountry = rhs.getCountry();
        int countryCompare = lhsCountry.compareTo(rhsCountry);
        if (0 == countryCompare)
        {
          String lhsVariant = lhs.getVariant();
          String rhsVariant = rhs.getVariant();
          return lhsVariant.compareTo(rhsVariant);
        }
        return countryCompare;
      }
      return langCompare;
    }
  }
}

META-INF /服务/ java.text.spi.DateFormatProvider:

dateformatproviders.DateFormatProviderImpl

测试程序:

package datetest;

import dateformatproviders.DateFormatProviderImpl;
import java.text.DateFormat;
import java.text.spi.DateFormatProvider;
import java.util.Date;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
import sun.util.LocaleServiceProviderPool;

public class Main
{
  /**
   * install the given dateFormatProvider for the default locale, using the default variant. <br/>
   * Changes the default locale
   *
   * @param dateFormatProvider
   */
  public static void install(DateFormatProviderImpl dateFormatProvider)
  {
    Locale originalDefaultLocale = Locale.getDefault();
    Locale modifiedDefaultLocale = DateFormatProviderImpl.createLocale(originalDefaultLocale, dateFormatProvider.getVariant());
    Locale.setDefault(modifiedDefaultLocale);
  }

  public static void main(String[] args) throws InterruptedException
  {
    install(new DateFormatProviderImpl());
    LocaleServiceProviderPool pool = LocaleServiceProviderPool.getPool(DateFormatProvider.class);
    boolean hasEntries = pool.hasProviders(); // is false
    while (true)
    {
      System.out.printf("%s\n", DateFormat.getDateTimeInstance().format(new Date()));
      TimeUnit.SECONDS.sleep(2);
    }

  }
}

在包含DateTest.jar的目录和一个包含DateFormatProvider.jar的文件夹lib执行:

java -cp DateTest.jar:lib/DateFormatProvider.jar dateTest.Main

生成默认格式化日期

当包含DateFormatProvider及其java.text.spi.DateFormatProvider文件的jar文件被复制到jre / lib / ext时,测试程序会工作。

1 个答案:

答案 0 :(得分:1)

根据official documentation关于可选包(这是JVM扩展的新名称),有两种方法可以将JAR文件用作可选包:

  • 放置在Java 2 Runtime Environment或JDK目录结构中的特殊位置 - 在这种情况下它是installed optional package

  • 从applet或应用程序的JAR文件的清单中以指定的方式引用 - 在这种情况下它是download optional package

将JAR放在类路径上并不足以将其作为可选包加载。但是当您将JAR文件放在jre/lib/ext目录中时,您正在使用第一种方式。

该文档还包含以下注释:

  

安装和下载可选包之间的另一个区别是   只有JAR文件中捆绑的applet和应用程序才能使用   下载可选包。未捆绑的小程序和应用程序   JAR文件没有可以引用下载的清单   可选包。

另请注意,已弃用已安装的可选包:

  

已弃用:已弃用对已安装的可选软件包的支持,可能会在将来的版本中将其删除。