Получить объект ClassLoader от вызывающей стороны - PullRequest
1 голос
/ 17 июня 2019

Я реализовал механизм плагинов и языковые пакеты, используя ResourceBundles в Java.

Это прекрасно работает, если я хочу получить ResourceBundle из основной программы (не из плагина).

Проблема в том, что я хочу добавить возможность создания ResourceBundle, который находится в плагине и работает только внутри плагина.

Плагины загружаются с использованием URLClassLoader s и Reflections. Я не могу получить доступ (не хочу) к плагину ClassLoader s из класса перевода. Таким образом, программа загружает плагин и позже выполняет метод внутри плагина (плагин отсутствует в Classpath), и этот плагин выполняет метод translate.

Для архивации я хочу получить объект ClassLoader из вызывающего метода.

Что-то вроде , это или , это может быть полезно, но я не вижу способа получить Class / ClassLoader, а не имя класса.

Я думал, что мог бы использовать Stacktrace для получения ClassLoader вызывающего метода, но я могу получить только имя, используя .getClassName и не Class или ClassLoader Object of Caller.

Вот что у меня есть:

перевести

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;
}

1 Ответ

2 голосов
/ 18 июня 2019

Я не думаю, что этот метод проб и ошибок является хорошей идеей. Ни один из них не выполняет повторную загрузку всех пакетов для каждой отдельной строки. Даже не кажется, что эта служба перевода добавляет значение по сравнению с альтернативой простого разрешения плагину читать свой пакет и вызывать 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;
}
...