从调用方获取 ClassLoader 对象
Get ClassLoader Object from Caller
我在 Java.
中使用 ResourceBundle 实现了插件机制和语言包
如果我想从核心程序(而不是插件)获取 ResourceBundle
,它工作得很好。
问题是我想增加创建一个 ResourceBundle
的可能性,它在插件中并且只在插件中工作。
使用 URLClassLoader
和 Reflections
加载插件。我无法访问(我不想)来自翻译 class 的插件 ClassLoader
s。
因此,程序加载插件并稍后在插件内部执行一个方法(插件不在类路径中)并且该插件执行翻译方法。
为了实现这个,我想从调用方法中获取 ClassLoader 对象。
像 this or this 这样的东西可能有用,但我没有找到获取 Class/ClassLoader 而不是 class 的名称的方法。
我以为我可以使用 Stacktrace 来获取调用方法的 ClassLoader 但我只能使用 .getClassName
获取名称而没有 Class
或 ClassLoader
的对象来电者。
这是我的:
翻译
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;
}
getResourceBundles
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
它并不比调用翻译服务的方法复杂。
为了完整起见,可以从 Java9 开始以标准方式获取调用者 class。然后,您可以像
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;
}
我在 Java.
中使用 ResourceBundle 实现了插件机制和语言包如果我想从核心程序(而不是插件)获取 ResourceBundle
,它工作得很好。
问题是我想增加创建一个 ResourceBundle
的可能性,它在插件中并且只在插件中工作。
使用 URLClassLoader
和 Reflections
加载插件。我无法访问(我不想)来自翻译 class 的插件 ClassLoader
s。
因此,程序加载插件并稍后在插件内部执行一个方法(插件不在类路径中)并且该插件执行翻译方法。
为了实现这个,我想从调用方法中获取 ClassLoader 对象。
像 this or this 这样的东西可能有用,但我没有找到获取 Class/ClassLoader 而不是 class 的名称的方法。
我以为我可以使用 Stacktrace 来获取调用方法的 ClassLoader 但我只能使用 .getClassName
获取名称而没有 Class
或 ClassLoader
的对象来电者。
这是我的:
翻译
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;
}
getResourceBundles
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
它并不比调用翻译服务的方法复杂。
为了完整起见,可以从 Java9 开始以标准方式获取调用者 class。然后,您可以像
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;
}