我以为我会在Java 8中使用新的ResourceBundleControlProvider
框架来修复Oracle本身永远无法修复的东西 - 读取资源包时使用的默认编码。
所以我做了一个控件:
package com.acme.resources;
import java.io.IOException;
import java.util.Locale;
import java.util.ResourceBundle;
public class AcmeResourceBundleControl extends ResourceBundle.Control
{
@Override
public ResourceBundle newBundle(String baseName, Locale locale, String format,
ClassLoader loader, boolean reload)
throws IllegalAccessException, InstantiationException, IOException
{
throw new UnsupportedOperationException("TODO");
}
}
然后我做了一个提供者:
package com.acme.resources;
import java.util.ResourceBundle;
import java.util.spi.ResourceBundleControlProvider;
public class AcmeResourceBundleControlProvider implements ResourceBundleControlProvider
{
private static final ResourceBundle.Control CONTROL = new AcmeResourceBundleControl();
@Override
public ResourceBundle.Control getControl(String baseName)
{
if (baseName.startsWith("com.acme."))
{
return CONTROL;
}
else
{
return null;
}
}
}
然后在META-INF / services / java.util.spi.ResourceBundleControlProvider中:
com.acme.resources.AcmeResourceBundleControlProvider
然后我只是尝试从IDEA运行我们的应用程序,我发现它从不加载我的提供程序(否则会引发异常。)
我检查了名字,他们似乎都匹配了。我检查了IDEA正在使用的编译器输出目录,它确实包含服务文件。我写了一个简单的测试程序,它只是试图查找服务:
public static void main(String[] args)
{
for (ResourceBundleControlProvider provider :
ServiceLoader.load(ResourceBundleControlProvider.class))
{
System.out.println(provider.getClass());
}
}
这会打印出一个条目,这是我的实现类的名称。所以问题是服务文件中的不是。
如果我在ResourceBundle中断点,我似乎能够访问自定义提供程序类。最初尝试调试器显示ServiceLoader没有找到任何实现,但我无法弄清楚原因。我确定有一些狡猾的类加载器魔法正在进行,这导致我的课程没有加载。 :(
the Javadoc上的一些可怕文档使得它可能必须作为全局扩展安装。如果确实如此,那有点遗憾,因为它似乎是一种有用的方式来覆盖默认(以及我认为已经破坏)的行为。但是我也在这个问题上阅读了the tutorial,它似乎没有描述这样的事情(除非在最后一分钟从Java 8中取出好的行为并且文档已经过时了!)< / p>
答案 0 :(得分:4)
本教程确实声明包含ResourceBundleControlProvider的JAR必须位于JVM的系统扩展目录中。 tutorial的第6节描述了要求:
java -Djava.ext.dirs = lib -cp build RBCPTest
安装Java扩展时,通常将扩展的JAR文件放在JRE的lib / ext目录中。但是,此命令指定包含具有系统属性java.ext.dirs。
的Java扩展的目录
ServiceLoader.loadInstalled()的JavaDoc还声明应用程序类路径上的提供程序被忽略。
答案 1 :(得分:0)
您的问题是JVM附带的java.util.ResourceBundle执行ServiceLoader.loadInstalled(ResourceBundleControlProvider.class)以获取静态初始化程序中的提供程序列表,并使用此后获得的列表。