从调用方获取类加载器对象



我已经在Java中使用ResourceBundles实现了插件机制和语言包。

如果我想从核心程序(而不是从插件)获取ResourceBundle,它工作得很好。

问题是我想添加创建插件中且仅在插件中工作的ResourceBundle的可能性。

插件使用URLClassLoaders 和Reflections加载。我无法访问(我不想)翻译类中的插件ClassLoader。 因此,程序加载插件并在稍后执行插件内部的方法(插件不在类路径中),并且该插件执行翻译方法。

为了存档这一点,我想从调用方法中获取类加载器对象。

像这样或这样的Somethng可能很有用,但我看不到获取Class/ClassLoader而不是类名称的方法。

我以为我可以使用 Stacktrace 来获取调用方法的类加载器,但我只能使用.getClassName而不是调用者的ClassClassLoader对象来获取名称。

这是我所拥有的:

翻译

public static String translate(Locale locale,String s) {
for (ResourceBundle bundle : getResourceBundles(locale/*,Thread.currentThread().getStackTrace()[1].getClassLoader();*/)) {
try {
return bundle.getString(s);
}catch (MissingResourceException e) {
//ignore/next iteration
}
}
return s;
}

获取资源包

private static Set<ResourceBundle> getResourceBundles(Locale locale,ClassLoader... loaders){
Set<ResourceBundle> bundles=new HashSet<>();
bundles.add(ResourceBundle.getBundle(BASE_NAME,locale,MyClass.class.getClassLoader()));
for (ClassLoader loader : loaders) {
ResourceBundle pluginBundle=getResourceBundle(g,loader);
if (pluginBundle!=null) {
bundles.add(pluginBundle);
}
}
return bundles;
}

我不认为这种试错法是一个好主意。也不是为每个字符串重新获取所有捆绑包。这个翻译服务似乎并没有增加一个价值,而不是让插件读取他们的捆绑包并调用getString,至少没有一个证明代码开销和复杂性的价值。

由于标准ResourceBundle.getBundle方法已经考虑了调用者的上下文,因此当字段声明和获取表达式放置在插件中并在其上调用getString时,将是一个微不足道的单行,并不比调用翻译服务的方法更复杂。

为了完整起见,从Java 9开始,可以以标准方式获取调用方类。然后,你可以像

private static final StackWalker STACK_WALKER
= StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
public static String translate(Locale locale, String s) {
for(ResourceBundle bundle: getResourceBundles(locale,
STACK_WALKER.getCallerClass().getClassLoader())) {
try {
return bundle.getString(s);
}catch (MissingResourceException e) {
//ignore/next iteration
}
}
return s;
}

最新更新